xref: /original-bsd/usr.bin/f77/pass1.tahoe/proc.c (revision 9acaf688)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)proc.c	5.2 (Berkeley) 6/9/85";
9 #endif not lint
10 
11 /*
12  * proc.c
13  *
14  * Routines for handling procedures, f77 compiler, pass 1.
15  *
16  * University of Utah CS Dept modification history:
17  *
18  * $Header: proc.c,v 3.11 85/06/04 03:45:29 donn Exp $
19  * $Log:	proc.c,v $
20  * Revision 3.11  85/06/04  03:45:29  donn
21  * Changed retval() to recognize that a function declaration might have
22  * bombed out earlier, leaving an error node behind...
23  *
24  * Revision 3.10  85/03/08  23:13:06  donn
25  * Finally figured out why function calls and array elements are not legal
26  * dummy array dimension declarator elements.  Hacked safedim() to stop 'em.
27  *
28  * Revision 3.9  85/02/02  00:26:10  donn
29  * Removed the call to entrystab() in enddcl() -- this was redundant (it was
30  * also done in startproc()) and confusing to dbx to boot.
31  *
32  * Revision 3.8  85/01/14  04:21:53  donn
33  * Added changes to implement Jerry's '-q' option.
34  *
35  * Revision 3.7  85/01/11  21:10:35  donn
36  * In conjunction with other changes to implement SAVE statements, function
37  * nameblocks were changed to make it appear that they are 'saved' too --
38  * this arranges things so that function return values are forced out of
39  * register before a return.
40  *
41  * Revision 3.6  84/12/10  19:27:20  donn
42  * comblock() signals an illegal common block name by returning a null pointer,
43  * but incomm() wasn't able to handle it, leading to core dumps.  I put the
44  * fix in incomm() to pick up null common blocks.
45  *
46  * Revision 3.5  84/11/21  20:33:31  donn
47  * It seems that I/O elements are treated as character strings so that their
48  * length can be passed to the I/O routines...  Unfortunately the compiler
49  * assumes that no temporaries can be of type CHARACTER and casually tosses
50  * length and type info away when removing TEMP blocks.  This has been fixed...
51  *
52  * Revision 3.4  84/11/05  22:19:30  donn
53  * Fixed a silly bug in the last fix.
54  *
55  * Revision 3.3  84/10/29  08:15:23  donn
56  * Added code to check the type and shape of subscript declarations,
57  * per Jerry Berkman's suggestion.
58  *
59  * Revision 3.2  84/10/29  05:52:07  donn
60  * Added change suggested by Jerry Berkman to report an error when an array
61  * is redimensioned.
62  *
63  * Revision 3.1  84/10/13  02:12:31  donn
64  * Merged Jerry Berkman's version into mine.
65  *
66  * Revision 2.1  84/07/19  12:04:09  donn
67  * Changed comment headers for UofU.
68  *
69  * Revision 1.6  84/07/19  11:32:15  donn
70  * Incorporated fix to setbound() to detect backward array subscript limits.
71  * The fix is by Bob Corbett, donated by Jerry Berkman.
72  *
73  * Revision 1.5  84/07/18  18:25:50  donn
74  * Fixed problem with doentry() where a placeholder for a return value
75  * was not allocated if the first entry didn't require one but a later
76  * entry did.
77  *
78  * Revision 1.4  84/05/24  20:52:09  donn
79  * Installed firewall #ifdef around the code that recycles stack temporaries,
80  * since it seems to be broken and lacks a good fix for the time being.
81  *
82  * Revision 1.3  84/04/16  09:50:46  donn
83  * Fixed mkargtemp() so that it only passes back a copy of a temporary, keeping
84  * the original for its own use.  This fixes a set of bugs that are caused by
85  * elements in the argtemplist getting stomped on.
86  *
87  * Revision 1.2  84/02/28  21:12:58  donn
88  * Added Berkeley changes for subroutine call argument temporaries fix.
89  *
90  */
91 
92 #include "defs.h"
93 
94 #ifdef SDB
95 #	include <a.out.h>
96 #	ifndef N_SO
97 #		include <stab.h>
98 #	endif
99 #endif
100 
101 extern flag namesflag;
102 
103 typedef
104   struct SizeList
105     {
106       struct SizeList *next;
107       ftnint size;
108       struct VarList *vars;
109     }
110   sizelist;
111 
112 
113 typedef
114   struct VarList
115     {
116       struct VarList *next;
117       Namep np;
118       struct Equivblock *ep;
119     }
120   varlist;
121 
122 
123 LOCAL sizelist *varsizes;
124 
125 
126 /* start a new procedure */
127 
128 newproc()
129 {
130 if(parstate != OUTSIDE)
131 	{
132 	execerr("missing end statement", CNULL);
133 	endproc();
134 	}
135 
136 parstate = INSIDE;
137 procclass = CLMAIN;	/* default */
138 }
139 
140 
141 
142 /* end of procedure. generate variables, epilogs, and prologs */
143 
144 endproc()
145 {
146 struct Labelblock *lp;
147 
148 if(parstate < INDATA)
149 	enddcl();
150 if(ctlstack >= ctls)
151 	err("DO loop or BLOCK IF not closed");
152 for(lp = labeltab ; lp < labtabend ; ++lp)
153 	if(lp->stateno!=0 && lp->labdefined==NO)
154 		errstr("missing statement number %s", convic(lp->stateno) );
155 
156 if (optimflag)
157   optimize();
158 
159 outiodata();
160 epicode();
161 procode();
162 donmlist();
163 dobss();
164 
165 #if FAMILY == PCC
166 	putbracket();
167 #endif
168 procinit();	/* clean up for next procedure */
169 }
170 
171 
172 
173 /* End of declaration section of procedure.  Allocate storage. */
174 
175 enddcl()
176 {
177 register struct Entrypoint *ep;
178 
179 parstate = INEXEC;
180 docommon();
181 doequiv();
182 docomleng();
183 for(ep = entries ; ep ; ep = ep->entnextp) {
184 	doentry(ep);
185 }
186 }
187 
188 /* ROUTINES CALLED WHEN ENCOUNTERING ENTRY POINTS */
189 
190 /* Main program or Block data */
191 
192 startproc(prgname, class)
193 Namep prgname;
194 int class;
195 {
196 struct Extsym *progname;
197 register struct Entrypoint *p;
198 
199 if(prgname)
200 	procname = prgname->varname;
201 if(namesflag == YES) {
202 	fprintf(diagfile, "   %s", (class==CLMAIN ? "MAIN" : "BLOCK DATA") );
203 	if(prgname)
204 		fprintf(diagfile, " %s", varstr(XL, procname) );
205 	fprintf(diagfile, ":\n");
206 	}
207 
208 if( prgname )
209 	progname = newentry( prgname );
210 else
211 	progname = NULL;
212 
213 p = ALLOC(Entrypoint);
214 if(class == CLMAIN)
215 	puthead("MAIN_", CLMAIN);
216 else
217 	puthead(CNULL, CLBLOCK);
218 if(class == CLMAIN)
219 	newentry( mkname(5, "MAIN") );
220 p->entryname = progname;
221 p->entrylabel = newlabel();
222 entries = p;
223 
224 procclass = class;
225 retlabel = newlabel();
226 #ifdef SDB
227 if(sdbflag) {
228          entrystab(p,class);
229 }
230 #endif
231 }
232 
233 /* subroutine or function statement */
234 
235 struct Extsym *newentry(v)
236 register Namep v;
237 {
238 register struct Extsym *p;
239 
240 p = mkext( varunder(VL, v->varname) );
241 
242 if(p==NULL || p->extinit || ! ONEOF(p->extstg, M(STGUNKNOWN)|M(STGEXT)) )
243 	{
244 	if(p == 0)
245 		dclerr("invalid entry name", v);
246 	else	dclerr("external name already used", v);
247 	return(0);
248 	}
249 v->vstg = STGAUTO;
250 v->vprocclass = PTHISPROC;
251 v->vclass = CLPROC;
252 p->extstg = STGEXT;
253 p->extinit = YES;
254 return(p);
255 }
256 
257 
258 entrypt(class, type, length, entname, args)
259 int class, type;
260 ftnint length;
261 Namep entname;
262 chainp args;
263 {
264 struct Extsym *entry;
265 register Namep q;
266 register struct Entrypoint *p, *ep;
267 
268 if(namesflag == YES) {
269 	if(class == CLENTRY)
270 		fprintf(diagfile, "       entry ");
271 	if(entname)
272 		fprintf(diagfile, "   %s", varstr(XL, entname->varname) );
273 	fprintf(diagfile, ":\n");
274 	}
275 
276 if( entname->vclass == CLPARAM ) {
277 	errstr("entry name %s used in 'parameter' statement",
278 		varstr(XL, entname->varname) );
279 	return;
280 	}
281 if( ((type == TYSUBR) || (class == CLENTRY && proctype == TYSUBR))
282 	&& (entname->vtype != TYUNKNOWN && entname->vtype != TYSUBR) ) {
283 	errstr("subroutine entry %s previously declared",
284 		varstr(XL, entname->varname) );
285 	return;
286 	}
287 if(  (entname->vstg != STGEXT && entname->vstg != STGUNKNOWN)
288 	||  (entname->vdim != NULL) ) {
289 	errstr("subroutine or function entry %s previously declared",
290 		varstr(XL, entname->varname) );
291 	return;
292 	}
293 
294 if( (class == CLPROC || class == CLENTRY) && type != TYSUBR )
295 	/* arrange to save function return values */
296 	entname->vsave = YES;
297 
298 entry = newentry( entname );
299 
300 if(class != CLENTRY)
301 	puthead( varstr(XL, procname = entry->extname), class);
302 q = mkname(VL, nounder(XL,entry->extname) );
303 
304 if( (type = lengtype(type, (int) length)) != TYCHAR)
305 	length = 0;
306 if(class == CLPROC)
307 	{
308 	procclass = CLPROC;
309 	proctype = type;
310 	procleng = length;
311 
312 	retlabel = newlabel();
313 	if(type == TYSUBR)
314 		ret0label = newlabel();
315 	}
316 
317 p = ALLOC(Entrypoint);
318 if(entries)	/* put new block at end of entries list */
319 	{
320 	for(ep = entries; ep->entnextp; ep = ep->entnextp)
321 		;
322 	ep->entnextp = p;
323 	}
324 else
325 	entries = p;
326 
327 p->entryname = entry;
328 p->arglist = args;
329 p->entrylabel = newlabel();
330 p->enamep = q;
331 
332 if(class == CLENTRY)
333 	{
334 	class = CLPROC;
335 	if(proctype == TYSUBR)
336 		type = TYSUBR;
337 	}
338 
339 q->vclass = class;
340 q->vprocclass = PTHISPROC;
341 settype(q, type, (int) length);
342 /* hold all initial entry points till end of declarations */
343 if(parstate >= INDATA) {
344 	doentry(p);
345 }
346 #ifdef SDB
347 	if(sdbflag)
348 	{ /* may need to preserve CLENTRY here */
349 	entrystab(p,class);
350 	}
351 #endif
352 }
353 
354 /* generate epilogs */
355 
356 LOCAL epicode()
357 {
358 register int i;
359 
360 if(procclass==CLPROC)
361 	{
362 	if(proctype==TYSUBR)
363 		{
364 		putlabel(ret0label);
365 		if(substars)
366 			putforce(TYINT, ICON(0) );
367 		putlabel(retlabel);
368 		goret(TYSUBR);
369 		}
370 	else	{
371 		putlabel(retlabel);
372 		if(multitype)
373 			{
374 			typeaddr = autovar(1, TYADDR, PNULL);
375 			putbranch( cpexpr(typeaddr) );
376 			for(i = 0; i < NTYPES ; ++i)
377 				if(rtvlabel[i] != 0)
378 					{
379 					putlabel(rtvlabel[i]);
380 					retval(i);
381 					}
382 			}
383 		else
384 			retval(proctype);
385 		}
386 	}
387 
388 else if(procclass != CLBLOCK)
389 	{
390 	putlabel(retlabel);
391 	goret(TYSUBR);
392 	}
393 }
394 
395 
396 /* generate code to return value of type  t */
397 
398 LOCAL retval(t)
399 register int t;
400 {
401 register Addrp p;
402 
403 switch(t)
404 	{
405 	case TYCHAR:
406 	case TYCOMPLEX:
407 	case TYDCOMPLEX:
408 		break;
409 
410 	case TYLOGICAL:
411 		t = tylogical;
412 	case TYADDR:
413 	case TYSHORT:
414 	case TYLONG:
415 		p = (Addrp) cpexpr(retslot);
416 		p->vtype = t;
417 		putforce(t, p);
418 		break;
419 
420 	case TYREAL:
421 	case TYDREAL:
422 		p = (Addrp) cpexpr(retslot);
423 		p->vtype = t;
424 		putforce(t, p);
425 		break;
426 
427 	case TYERROR:
428 		return;		/* someone else already complained */
429 
430 	default:
431 		badtype("retval", t);
432 	}
433 goret(t);
434 }
435 
436 
437 /* Allocate extra argument array if needed. Generate prologs. */
438 
439 LOCAL procode()
440 {
441 register struct Entrypoint *p;
442 Addrp argvec;
443 
444 #if TARGET==GCOS
445 	argvec = autovar(lastargslot/SZADDR, TYADDR, PNULL);
446 #else
447 	if(lastargslot>0 && nentry>1)
448 #if TARGET == VAX || TARGET == TAHOE
449 		argvec = autovar(1 + lastargslot/SZADDR, TYADDR, PNULL);
450 #else
451 		argvec = autovar(lastargslot/SZADDR, TYADDR, PNULL);
452 #endif
453 	else
454 		argvec = NULL;
455 #endif
456 
457 
458 #if TARGET == PDP11
459 	/* for the optimizer */
460 	if(fudgelabel)
461 		putlabel(fudgelabel);
462 #endif
463 
464 for(p = entries ; p ; p = p->entnextp)
465 	prolog(p, argvec);
466 
467 #if FAMILY == PCC
468 	putrbrack(procno);
469 #endif
470 
471 prendproc();
472 }
473 
474 
475 /*
476    manipulate argument lists (allocate argument slot positions)
477  * keep track of return types and labels
478  */
479 
480 LOCAL doentry(ep)
481 struct Entrypoint *ep;
482 {
483 register int type;
484 register Namep np;
485 chainp p;
486 register Namep q;
487 Addrp mkarg();
488 
489 ++nentry;
490 if(procclass == CLMAIN)
491 	{
492 	if (optimflag)
493 		optbuff (SKLABEL, 0, ep->entrylabel, 0);
494 	else
495 		putlabel(ep->entrylabel);
496 	return;
497 	}
498 else if(procclass == CLBLOCK)
499 	return;
500 
501 impldcl( np = mkname(VL, nounder(XL, ep->entryname->extname) ) );
502 type = np->vtype;
503 if(proctype == TYUNKNOWN)
504 	if( (proctype = type) == TYCHAR)
505 		procleng = (np->vleng ? np->vleng->constblock.const.ci : (ftnint) (-1));
506 
507 if(proctype == TYCHAR)
508 	{
509 	if(type != TYCHAR)
510 		err("noncharacter entry of character function");
511 	else if( (np->vleng ? np->vleng->constblock.const.ci : (ftnint) (-1)) != procleng)
512 		err("mismatched character entry lengths");
513 	}
514 else if(type == TYCHAR)
515 	err("character entry of noncharacter function");
516 else if(type != proctype)
517 	multitype = YES;
518 if(rtvlabel[type] == 0)
519 	rtvlabel[type] = newlabel();
520 ep->typelabel = rtvlabel[type];
521 
522 if(type == TYCHAR)
523 	{
524 	if(chslot < 0)
525 		{
526 		chslot = nextarg(TYADDR);
527 		chlgslot = nextarg(TYLENG);
528 		}
529 	np->vstg = STGARG;
530 	np->vardesc.varno = chslot;
531 	if(procleng < 0)
532 		np->vleng = (expptr) mkarg(TYLENG, chlgslot);
533 	}
534 else if( ISCOMPLEX(type) )
535 	{
536 	np->vstg = STGARG;
537 	if(cxslot < 0)
538 		cxslot = nextarg(TYADDR);
539 	np->vardesc.varno = cxslot;
540 	}
541 else if(type != TYSUBR)
542 	{
543 	if(retslot == NULL)
544 		retslot = autovar(1, TYDREAL, PNULL);
545 	np->vstg = STGAUTO;
546 	np->voffset = retslot->memoffset->constblock.const.ci;
547 	}
548 
549 for(p = ep->arglist ; p ; p = p->nextp)
550 	if(! (( q = (Namep) (p->datap) )->vdcldone) )
551 		q->vardesc.varno = nextarg(TYADDR);
552 
553 for(p = ep->arglist ; p ; p = p->nextp)
554 	if(! (( q = (Namep) (p->datap) )->vdcldone) )
555 		{
556 		impldcl(q);
557 		q->vdcldone = YES;
558 		if(q->vtype == TYCHAR)
559 			{
560 			if(q->vleng == NULL)	/* character*(*) */
561 				q->vleng = (expptr)
562 						mkarg(TYLENG, nextarg(TYLENG) );
563 			else if(nentry == 1)
564 				nextarg(TYLENG);
565 			}
566 		else if(q->vclass==CLPROC && nentry==1)
567 			nextarg(TYLENG) ;
568 #ifdef SDB
569 		if(sdbflag) {
570 			namestab(q);
571 		}
572 #endif
573 		}
574 
575 if (optimflag)
576 	optbuff (SKLABEL, 0, ep->entrylabel, 0);
577 else
578 	putlabel(ep->entrylabel);
579 }
580 
581 
582 
583 LOCAL nextarg(type)
584 int type;
585 {
586 int k;
587 k = lastargslot;
588 lastargslot += typesize[type];
589 return(k);
590 }
591 
592 /* generate variable references */
593 
594 LOCAL dobss()
595 {
596 register struct Hashentry *p;
597 register Namep q;
598 register int i;
599 int align;
600 ftnint leng, iarrl;
601 char *memname();
602 int qstg, qclass, qtype;
603 
604 pruse(asmfile, USEBSS);
605 varsizes = NULL;
606 
607 for(p = hashtab ; p<lasthash ; ++p)
608     if(q = p->varp)
609 	{
610 	qstg = q->vstg;
611 	qtype = q->vtype;
612 	qclass = q->vclass;
613 
614 	if( (qclass==CLUNKNOWN && qstg!=STGARG) ||
615 	    (qclass==CLVAR && qstg==STGUNKNOWN) )
616 		warn1("local variable %s never used", varstr(VL,q->varname) );
617 	else if(qclass==CLPROC && q->vprocclass==PEXTERNAL && qstg!=STGARG)
618 		mkext(varunder(VL, q->varname)) ->extstg = STGEXT;
619 
620 	if (qclass == CLVAR && qstg == STGBSS)
621 	  {
622 	    if (SMALLVAR(q->varsize))
623 	      {
624 		enlist(q->varsize, q, NULL);
625 		q->inlcomm = NO;
626 	      }
627 	    else
628 	      {
629 		if (q->init == NO)
630 		  {
631 		    preven(ALIDOUBLE);
632 		    prlocvar(memname(qstg, q->vardesc.varno), q->varsize);
633 		    q->inlcomm = YES;
634 		  }
635 		else
636 		  prlocdata(memname(qstg, q->vardesc.varno), q->varsize,
637 			    q->vtype, q->initoffset, &(q->inlcomm));
638 	      }
639 	  }
640 	else if(qclass==CLVAR && qstg!=STGARG)
641 		{
642 		if(q->vdim && !ISICON(q->vdim->nelt) )
643 			dclerr("adjustable dimension on non-argument", q);
644 		if(qtype==TYCHAR && (q->vleng==NULL || !ISICON(q->vleng)))
645 			dclerr("adjustable leng on nonargument", q);
646 		}
647 
648 	chkdim(q);
649 	}
650 
651 for (i = 0 ; i < nequiv ; ++i)
652   if ( (leng = eqvclass[i].eqvleng) != 0 )
653     {
654       if (SMALLVAR(leng))
655 	enlist(leng, NULL, eqvclass + i);
656       else if (eqvclass[i].init == NO)
657 	{
658 	  preven(ALIDOUBLE);
659 	  prlocvar(memname(STGEQUIV, i), leng);
660 	  eqvclass[i].inlcomm = YES;
661 	}
662       else
663 	prlocdata(memname(STGEQUIV, i), leng, TYDREAL,
664 		  eqvclass[i].initoffset, &(eqvclass[i].inlcomm));
665     }
666 
667   outlocvars();
668 #ifdef SDB
669     if(sdbflag) {
670       for(p = hashtab ; p<lasthash ; ++p) if(q = p->varp) {
671 	  qstg = q->vstg;
672 	  qclass = q->vclass;
673           if( ONEOF(qclass, M(CLVAR))) {
674 	     if (! ONEOF(qstg,M(STGCOMMON)|M(STGARG) ) ) namestab(q);
675 	  }
676       }
677     }
678 #endif
679 
680   close(vdatafile);
681   close(vchkfile);
682   unlink(vdatafname);
683   unlink(vchkfname);
684   vdatahwm = 0;
685 }
686 
687 
688 
689 donmlist()
690 {
691 register struct Hashentry *p;
692 register Namep q;
693 
694 pruse(asmfile, USEINIT);
695 
696 for(p=hashtab; p<lasthash; ++p)
697 	if( (q = p->varp) && q->vclass==CLNAMELIST)
698 		namelist(q);
699 }
700 
701 
702 doext()
703 {
704 struct Extsym *p;
705 
706 for(p = extsymtab ; p<nextext ; ++p)
707 	prext(p);
708 }
709 
710 
711 
712 
713 ftnint iarrlen(q)
714 register Namep q;
715 {
716 ftnint leng;
717 
718 leng = typesize[q->vtype];
719 if(leng <= 0)
720 	return(-1);
721 if(q->vdim)
722 	if( ISICON(q->vdim->nelt) )
723 		leng *= q->vdim->nelt->constblock.const.ci;
724 	else	return(-1);
725 if(q->vleng)
726 	if( ISICON(q->vleng) )
727 		leng *= q->vleng->constblock.const.ci;
728 	else 	return(-1);
729 return(leng);
730 }
731 
732 /* This routine creates a static block representing the namelist.
733    An equivalent declaration of the structure produced is:
734 	struct namelist
735 		{
736 		char namelistname[16];
737 		struct namelistentry
738 			{
739 			char varname[16];
740 			char *varaddr;
741 			int type; # negative means -type= number of chars
742 			struct dimensions *dimp; # null means scalar
743 			} names[];
744 		};
745 
746 	struct dimensions
747 		{
748 		int numberofdimensions;
749 		int numberofelements
750 		int baseoffset;
751 		int span[numberofdimensions];
752 		};
753    where the namelistentry list terminates with a null varname
754    If dimp is not null, then the corner element of the array is at
755    varaddr.  However,  the element with subscripts (i1,...,in) is at
756    varaddr - dimp->baseoffset + sizeoftype * (i1+span[0]*(i2+span[1]*...)
757 */
758 
759 namelist(np)
760 Namep np;
761 {
762 register chainp q;
763 register Namep v;
764 register struct Dimblock *dp;
765 char *memname();
766 int type, dimno, dimoffset;
767 flag bad;
768 
769 
770 preven(ALILONG);
771 fprintf(asmfile, LABELFMT, memname(STGINIT, np->vardesc.varno));
772 putstr(asmfile, varstr(VL, np->varname), 16);
773 dimno = ++lastvarno;
774 dimoffset = 0;
775 bad = NO;
776 
777 for(q = np->varxptr.namelist ; q ; q = q->nextp)
778 	{
779 	vardcl( v = (Namep) (q->datap) );
780 	type = v->vtype;
781 	if( ONEOF(v->vstg, MSKSTATIC) )
782 		{
783 		preven(ALILONG);
784 		putstr(asmfile, varstr(VL,v->varname), 16);
785 		praddr(asmfile, v->vstg, v->vardesc.varno, v->voffset);
786 		prconi(asmfile, TYINT,
787 			type==TYCHAR ?
788 			    -(v->vleng->constblock.const.ci) : (ftnint) type);
789 		if(v->vdim)
790 			{
791 			praddr(asmfile, STGINIT, dimno, (ftnint)dimoffset);
792 			dimoffset += 3 + v->vdim->ndim;
793 			}
794 		else
795 			praddr(asmfile, STGNULL,0,(ftnint) 0);
796 		}
797 	else
798 		{
799 		dclerr("may not appear in namelist", v);
800 		bad = YES;
801 		}
802 	}
803 
804 if(bad)
805 	return;
806 
807 putstr(asmfile, "", 16);
808 
809 if(dimoffset > 0)
810 	{
811 	fprintf(asmfile, LABELFMT, memname(STGINIT,dimno));
812 	for(q = np->varxptr.namelist ; q ; q = q->nextp)
813 		if(dp = q->datap->nameblock.vdim)
814 			{
815 			int i;
816 			prconi(asmfile, TYINT, (ftnint) (dp->ndim) );
817 			prconi(asmfile, TYINT,
818 				(ftnint) (dp->nelt->constblock.const.ci) );
819 			prconi(asmfile, TYINT,
820 				(ftnint) (dp->baseoffset->constblock.const.ci));
821 			for(i=0; i<dp->ndim ; ++i)
822 				prconi(asmfile, TYINT,
823 					dp->dims[i].dimsize->constblock.const.ci);
824 			}
825 	}
826 
827 }
828 
829 LOCAL docommon()
830 {
831 register struct Extsym *p;
832 register chainp q;
833 struct Dimblock *t;
834 expptr neltp;
835 register Namep v;
836 ftnint size;
837 int type;
838 
839 for(p = extsymtab ; p<nextext ; ++p)
840 	if(p->extstg==STGCOMMON)
841 		{
842 #ifdef SDB
843 		if(sdbflag)
844 			prstab(varstr(XL,p->extname), N_BCOMM, 0, 0);
845 #endif
846 		for(q = p->extp ; q ; q = q->nextp)
847 			{
848 			v = (Namep) (q->datap);
849 			if(v->vdcldone == NO)
850 				vardcl(v);
851 			type = v->vtype;
852 			if(p->extleng % typealign[type] != 0)
853 				{
854 				dclerr("common alignment", v);
855 				p->extleng = roundup(p->extleng, typealign[type]);
856 				}
857 			v->voffset = p->extleng;
858 			v->vardesc.varno = p - extsymtab;
859 			if(type == TYCHAR)
860 				size = v->vleng->constblock.const.ci;
861 			else	size = typesize[type];
862 			if(t = v->vdim)
863 				if( (neltp = t->nelt) && ISCONST(neltp) )
864 					size *= neltp->constblock.const.ci;
865 				else
866 					dclerr("adjustable array in common", v);
867 			p->extleng += size;
868 #ifdef SDB
869 			if(sdbflag)
870 				{
871 				namestab(v);
872 				}
873 #endif
874 			}
875 
876 		frchain( &(p->extp) );
877 #ifdef SDB
878 		if(sdbflag)
879 			prstab(varstr(XL,p->extname), N_ECOMM, 0, 0);
880 #endif
881 		}
882 }
883 
884 
885 
886 
887 
888 LOCAL docomleng()
889 {
890 register struct Extsym *p;
891 
892 for(p = extsymtab ; p < nextext ; ++p)
893 	if(p->extstg == STGCOMMON)
894 		{
895 		if(p->maxleng!=0 && p->extleng!=0 && p->maxleng!=p->extleng
896 		    && !eqn(XL,"_BLNK__ ",p->extname) )
897 			warn1("incompatible lengths for common block %s",
898 				nounder(XL, p->extname) );
899 		if(p->maxleng < p->extleng)
900 			p->maxleng = p->extleng;
901 		p->extleng = 0;
902 	}
903 }
904 
905 
906 
907 
908 /* ROUTINES DEALING WITH AUTOMATIC AND TEMPORARY STORAGE */
909 
910 /*  frees a temporary block  */
911 
912 frtemp(p)
913 Tempp p;
914 {
915 Addrp t;
916 
917 if (optimflag)
918 	{
919 	if (p->tag != TTEMP)
920 		badtag ("frtemp",p->tag);
921 	t = p->memalloc;
922 	}
923 else
924 	t = (Addrp) p;
925 
926 /* restore clobbered character string lengths */
927 if(t->vtype==TYCHAR && t->varleng!=0)
928 	{
929 	frexpr(t->vleng);
930 	t->vleng = ICON(t->varleng);
931 	}
932 
933 /* put block on chain of temps to be reclaimed */
934 holdtemps = mkchain(t, holdtemps);
935 }
936 
937 
938 
939 /* allocate an automatic variable slot */
940 
941 Addrp autovar(nelt, t, lengp)
942 register int nelt, t;
943 expptr lengp;
944 {
945 ftnint leng;
946 register Addrp q;
947 
948 if(lengp)
949 	if( ISICON(lengp) )
950 		leng = lengp->constblock.const.ci;
951 	else	{
952 		fatal("automatic variable of nonconstant length");
953 		}
954 else
955 	leng = typesize[t];
956 autoleng = roundup( autoleng, typealign[t]);
957 
958 q = ALLOC(Addrblock);
959 q->tag = TADDR;
960 q->vtype = t;
961 if(lengp)
962 	{
963 	q->vleng = ICON(leng);
964 	q->varleng = leng;
965 	}
966 q->vstg = STGAUTO;
967 q->memno = newlabel();
968 q->ntempelt = nelt;
969 #if TARGET==PDP11 || TARGET==VAX || TARGET == TAHOE
970 	/* stack grows downward */
971 	autoleng += nelt*leng;
972 	q->memoffset = ICON( - autoleng );
973 #else
974 	q->memoffset = ICON( autoleng );
975 	autoleng += nelt*leng;
976 #endif
977 
978 return(q);
979 }
980 
981 
982 
983 /*
984  *  create a temporary block (TTEMP) when optimizing,
985  *  an ordinary TADDR block when not optimizing
986  */
987 
988 Tempp mktmpn(nelt, type, lengp)
989 int nelt;
990 register int type;
991 expptr lengp;
992 {
993 ftnint leng;
994 chainp p, oldp;
995 register Tempp q;
996 Addrp altemp;
997 
998 if (! optimflag)
999 	return ( (Tempp) mkaltmpn(nelt,type,lengp) );
1000 if(type==TYUNKNOWN || type==TYERROR)
1001 	badtype("mktmpn", type);
1002 
1003 if(type==TYCHAR)
1004 	if( ISICON(lengp) )
1005 		leng = lengp->constblock.const.ci;
1006 	else	{
1007 		err("adjustable length");
1008 		return( (Tempp) errnode() );
1009 		}
1010 else
1011 	leng = typesize[type];
1012 
1013 q = ALLOC(Tempblock);
1014 q->tag = TTEMP;
1015 q->vtype = type;
1016 if(type == TYCHAR)
1017 	{
1018 	q->vleng = ICON(leng);
1019 	q->varleng = leng;
1020 	}
1021 
1022 altemp = ALLOC(Addrblock);
1023 altemp->tag = TADDR;
1024 altemp->vstg = STGUNKNOWN;
1025 q->memalloc = altemp;
1026 
1027 q->ntempelt = nelt;
1028 q->istemp = YES;
1029 return(q);
1030 }
1031 
1032 
1033 
1034 Addrp mktemp(type, lengp)
1035 int type;
1036 expptr lengp;
1037 {
1038 return( (Addrp) mktmpn(1,type,lengp) );
1039 }
1040 
1041 
1042 
1043 /*  allocate a temporary location for the given temporary block;
1044     if already allocated, return its location  */
1045 
1046 Addrp altmpn(tp)
1047 Tempp tp;
1048 
1049 {
1050 Addrp t, q;
1051 
1052 if (tp->tag != TTEMP)
1053 	badtag ("altmpn",tp->tag);
1054 
1055 t = tp->memalloc;
1056 if (t->vstg != STGUNKNOWN)
1057 	{
1058 	if (tp->vtype == TYCHAR)
1059 		{
1060 		/*
1061 		 * Unformatted I/O parameters are treated like character
1062 		 *	strings (sigh) -- propagate type and length.
1063 		 */
1064 		t = (Addrp) cpexpr(t);
1065 		t->vtype = tp->vtype;
1066 		t->vleng = tp->vleng;
1067 		t->varleng = tp->varleng;
1068 		}
1069 	return (t);
1070 	}
1071 
1072 q = mkaltmpn (tp->ntempelt, tp->vtype, tp->vleng);
1073 cpn (sizeof(struct Addrblock), (char*)q, (char*)t);
1074 free ( (charptr) q);
1075 return(t);
1076 }
1077 
1078 
1079 
1080 /*  create and allocate space immediately for a temporary  */
1081 
1082 Addrp mkaltemp(type,lengp)
1083 int type;
1084 expptr lengp;
1085 {
1086 return (mkaltmpn(1,type,lengp));
1087 }
1088 
1089 
1090 
1091 Addrp mkaltmpn(nelt,type,lengp)
1092 int nelt;
1093 register int type;
1094 expptr lengp;
1095 {
1096 ftnint leng;
1097 chainp p, oldp;
1098 register Addrp q;
1099 
1100 if(type==TYUNKNOWN || type==TYERROR)
1101 	badtype("mkaltmpn", type);
1102 
1103 if(type==TYCHAR)
1104 	if( ISICON(lengp) )
1105 		leng = lengp->constblock.const.ci;
1106 	else	{
1107 		err("adjustable length");
1108 		return( (Addrp) errnode() );
1109 		}
1110 
1111 /*
1112  * if a temporary of appropriate shape is on the templist,
1113  * remove it from the list and return it
1114  */
1115 
1116 #ifdef notdef
1117 /*
1118  * This code is broken until SKFRTEMP slots can be processed in putopt()
1119  *	instead of in optimize() -- all kinds of things in putpcc.c can
1120  *	bomb because of this.  Sigh.
1121  */
1122 for(oldp=CHNULL, p=templist  ;  p  ;  oldp=p, p=p->nextp)
1123 	{
1124 	q = (Addrp) (p->datap);
1125 	if(q->vtype==type && q->ntempelt==nelt &&
1126 	    (type!=TYCHAR || q->vleng->constblock.const.ci==leng) )
1127 		{
1128 		if(oldp)
1129 			oldp->nextp = p->nextp;
1130 		else
1131 			templist = p->nextp;
1132 		free( (charptr) p);
1133 
1134 		if (debugflag[14])
1135 			fprintf(diagfile,"mkaltmpn reusing offset %d\n",
1136 				q->memoffset->constblock.const.ci);
1137 		return(q);
1138 		}
1139 	}
1140 #endif notdef
1141 q = autovar(nelt, type, lengp);
1142 q->istemp = YES;
1143 
1144 if (debugflag[14])
1145 	fprintf(diagfile,"mkaltmpn new offset %d\n",
1146 		q->memoffset->constblock.const.ci);
1147 return(q);
1148 }
1149 
1150 
1151 
1152 /*  The following routine is a patch which is only needed because the	*/
1153 /*  code for processing actual arguments for calls does not allocate	*/
1154 /*  the temps it needs before optimization takes place.  A better	*/
1155 /*  solution is possible, but I do not have the time to implement it	*/
1156 /*  now.								*/
1157 /*									*/
1158 /*					Robert P. Corbett		*/
1159 
1160 Addrp
1161 mkargtemp(type, lengp)
1162 int type;
1163 expptr lengp;
1164 {
1165   ftnint leng;
1166   chainp oldp, p;
1167   Addrp q;
1168 
1169   if (type == TYUNKNOWN || type == TYERROR)
1170     badtype("mkargtemp", type);
1171 
1172   if (type == TYCHAR)
1173     {
1174       if (ISICON(lengp))
1175 	leng = lengp->constblock.const.ci;
1176       else
1177 	{
1178 	  err("adjustable length");
1179 	  return ((Addrp) errnode());
1180 	}
1181     }
1182 
1183   oldp = CHNULL;
1184   p = argtemplist;
1185 
1186   while (p)
1187     {
1188       q = (Addrp) (p->datap);
1189       if (q->vtype == type
1190 	  && (type != TYCHAR || q->vleng->constblock.const.ci == leng))
1191 	{
1192 	  if (oldp)
1193 	    oldp->nextp = p->nextp;
1194 	  else
1195 	    argtemplist = p->nextp;
1196 
1197 	  p->nextp = activearglist;
1198 	  activearglist = p;
1199 
1200 	  return ((Addrp) cpexpr(q));
1201 	}
1202 
1203       oldp = p;
1204       p = p->nextp;
1205     }
1206 
1207   q = autovar(1, type, lengp);
1208   activearglist = mkchain(q, activearglist);
1209   return ((Addrp) cpexpr(q));
1210 }
1211 
1212 /* VARIOUS ROUTINES FOR PROCESSING DECLARATIONS */
1213 
1214 struct Extsym *comblock(len, s)
1215 register int len;
1216 register char *s;
1217 {
1218 struct Extsym *p;
1219 
1220 if(len == 0)
1221 	{
1222 	s = BLANKCOMMON;
1223 	len = strlen(s);
1224 	}
1225 p = mkext( varunder(len, s) );
1226 if(p->extstg == STGUNKNOWN)
1227 	p->extstg = STGCOMMON;
1228 else if(p->extstg != STGCOMMON)
1229 	{
1230 	errstr("%s cannot be a common block name", s);
1231 	return(0);
1232 	}
1233 
1234 return( p );
1235 }
1236 
1237 
1238 incomm(c, v)
1239 struct Extsym *c;
1240 Namep v;
1241 {
1242 if(v->vstg != STGUNKNOWN)
1243 	dclerr("incompatible common declaration", v);
1244 else
1245 	{
1246 	if(c == (struct Extsym *) 0)
1247 		return;		/* Illegal common block name upstream */
1248 	v->vstg = STGCOMMON;
1249 	c->extp = hookup(c->extp, mkchain(v,CHNULL) );
1250 	}
1251 }
1252 
1253 
1254 
1255 
1256 settype(v, type, length)
1257 register Namep  v;
1258 register int type;
1259 register int length;
1260 {
1261 if(type == TYUNKNOWN)
1262 	return;
1263 
1264 if(type==TYSUBR && v->vtype!=TYUNKNOWN && v->vstg==STGARG)
1265 	{
1266 	v->vtype = TYSUBR;
1267 	frexpr(v->vleng);
1268 	}
1269 else if(type < 0)	/* storage class set */
1270 	{
1271 	if(v->vstg == STGUNKNOWN)
1272 		v->vstg = - type;
1273 	else if(v->vstg != -type)
1274 		dclerr("incompatible storage declarations", v);
1275 	}
1276 else if(v->vtype == TYUNKNOWN)
1277 	{
1278 	if( (v->vtype = lengtype(type, length))==TYCHAR && length>=0)
1279 		v->vleng = ICON(length);
1280 	}
1281 else if(v->vtype!=type || (type==TYCHAR && v->vleng->constblock.const.ci!=length) )
1282 	dclerr("incompatible type declarations", v);
1283 }
1284 
1285 
1286 
1287 
1288 
1289 lengtype(type, length)
1290 register int type;
1291 register int length;
1292 {
1293 switch(type)
1294 	{
1295 	case TYREAL:
1296 		if(length == 8)
1297 			return(TYDREAL);
1298 		if(length == 4)
1299 			goto ret;
1300 		break;
1301 
1302 	case TYCOMPLEX:
1303 		if(length == 16)
1304 			return(TYDCOMPLEX);
1305 		if(length == 8)
1306 			goto ret;
1307 		break;
1308 
1309 	case TYSHORT:
1310 	case TYDREAL:
1311 	case TYDCOMPLEX:
1312 	case TYCHAR:
1313 	case TYUNKNOWN:
1314 	case TYSUBR:
1315 	case TYERROR:
1316 		goto ret;
1317 
1318 	case TYLOGICAL:
1319 		if(length == typesize[TYLOGICAL])
1320 			goto ret;
1321 		break;
1322 
1323 	case TYLONG:
1324 		if(length == 0 )
1325 			return(tyint);
1326 		if(length == 2)
1327 			return(TYSHORT);
1328 		if(length == 4 )
1329 			goto ret;
1330 		break;
1331 	default:
1332 		badtype("lengtype", type);
1333 	}
1334 
1335 if(length != 0)
1336 	err("incompatible type-length combination");
1337 
1338 ret:
1339 	return(type);
1340 }
1341 
1342 
1343 
1344 
1345 
1346 setintr(v)
1347 register Namep  v;
1348 {
1349 register int k;
1350 
1351 if(v->vstg == STGUNKNOWN)
1352 	v->vstg = STGINTR;
1353 else if(v->vstg!=STGINTR)
1354 	dclerr("incompatible use of intrinsic function", v);
1355 if(v->vclass==CLUNKNOWN)
1356 	v->vclass = CLPROC;
1357 if(v->vprocclass == PUNKNOWN)
1358 	v->vprocclass = PINTRINSIC;
1359 else if(v->vprocclass != PINTRINSIC)
1360 	dclerr("invalid intrinsic declaration", v);
1361 if(k = intrfunct(v->varname))
1362 	v->vardesc.varno = k;
1363 else
1364 	dclerr("unknown intrinsic function", v);
1365 }
1366 
1367 
1368 
1369 setext(v)
1370 register Namep  v;
1371 {
1372 if(v->vclass == CLUNKNOWN)
1373 	v->vclass = CLPROC;
1374 else if(v->vclass != CLPROC)
1375 	dclerr("conflicting declarations", v);
1376 
1377 if(v->vprocclass == PUNKNOWN)
1378 	v->vprocclass = PEXTERNAL;
1379 else if(v->vprocclass != PEXTERNAL)
1380 	dclerr("conflicting declarations", v);
1381 }
1382 
1383 
1384 
1385 
1386 /* create dimensions block for array variable */
1387 
1388 setbound(v, nd, dims)
1389 register Namep  v;
1390 int nd;
1391 struct { expptr lb, ub; } dims[ ];
1392 {
1393 register expptr q, t;
1394 register struct Dimblock *p;
1395 int i;
1396 
1397 if(v->vclass == CLUNKNOWN)
1398 	v->vclass = CLVAR;
1399 else if(v->vclass != CLVAR)
1400 	{
1401 	dclerr("only variables may be arrays", v);
1402 	return;
1403 	}
1404 if(v->vdim)
1405 	{
1406 	dclerr("redimensioned array", v);
1407 	return;
1408 	}
1409 
1410 v->vdim = p = (struct Dimblock *)
1411 		ckalloc( sizeof(int) + (3+6*nd)*sizeof(expptr) );
1412 p->ndim = nd;
1413 p->nelt = ICON(1);
1414 
1415 for(i=0 ; i<nd ; ++i)
1416 	{
1417 #ifdef SDB
1418         if(sdbflag) {
1419 /* Save the bounds trees built up by the grammar routines for use in stabs */
1420 
1421 		if(dims[i].lb == NULL) p->dims[i].lb=ICON(1);
1422         	else p->dims[i].lb= (expptr) cpexpr(dims[i].lb);
1423                 if(ISCONST(p->dims[i].lb)) p->dims[i].lbaddr = (expptr) PNULL;
1424                 else p->dims[i].lbaddr = (expptr) autovar(1, tyint, PNULL);
1425 
1426 		if(dims[i].ub == NULL) p->dims[i].ub=ICON(1);
1427         	else p->dims[i].ub = (expptr) cpexpr(dims[i].ub);
1428                 if(ISCONST(p->dims[i].ub)) p->dims[i].ubaddr = (expptr) PNULL;
1429                 else p->dims[i].ubaddr = (expptr) autovar(1, tyint, PNULL);
1430 	}
1431 #endif
1432 	if( (q = dims[i].ub) == NULL)
1433 		{
1434 		if(i == nd-1)
1435 			{
1436 			frexpr(p->nelt);
1437 			p->nelt = NULL;
1438 			}
1439 		else
1440 			err("only last bound may be asterisk");
1441 		p->dims[i].dimsize = ICON(1);;
1442 		p->dims[i].dimexpr = NULL;
1443 		}
1444 	else
1445 		{
1446 		if(dims[i].lb)
1447 			{
1448 			q = mkexpr(OPMINUS, q, cpexpr(dims[i].lb));
1449 			q = mkexpr(OPPLUS, q, ICON(1) );
1450 			}
1451 		if( ISCONST(q) )
1452 			{
1453 			if (!ISINT(q->headblock.vtype)) {
1454 			   dclerr("dimension bounds must be integer expression", v);
1455 			   frexpr(q);
1456 			   q = ICON(0);
1457 			   }
1458 			if ( q->constblock.const.ci <= 0)
1459 			   {
1460 			   dclerr("array bounds out of sequence", v);
1461 			   frexpr(q);
1462 			   q = ICON(0);
1463 			   }
1464 			p->dims[i].dimsize = q;
1465 			p->dims[i].dimexpr = (expptr) PNULL;
1466 			}
1467 		else	{
1468 			p->dims[i].dimsize = (expptr) autovar(1, tyint, PNULL);
1469 			p->dims[i].dimexpr = q;
1470 			}
1471 		if(p->nelt)
1472 			p->nelt = mkexpr(OPSTAR, p->nelt,
1473 					cpexpr(p->dims[i].dimsize) );
1474 		}
1475 	}
1476 
1477 q = dims[nd-1].lb;
1478 if(q == NULL)
1479 	q = ICON(1);
1480 
1481 for(i = nd-2 ; i>=0 ; --i)
1482 	{
1483 	t = dims[i].lb;
1484 	if(t == NULL)
1485 		t = ICON(1);
1486 	if(p->dims[i].dimsize)
1487 		q = mkexpr(OPPLUS, t, mkexpr(OPSTAR, cpexpr(p->dims[i].dimsize), q) );
1488 	}
1489 
1490 if( ISCONST(q) )
1491 	{
1492 	p->baseoffset = q;
1493 	p->basexpr = NULL;
1494 	}
1495 else
1496 	{
1497 	p->baseoffset = (expptr) autovar(1, tyint, PNULL);
1498 	p->basexpr = q;
1499 	}
1500 }
1501 
1502 
1503 
1504 /*
1505  * Check the dimensions of q to ensure that they are appropriately defined.
1506  */
1507 LOCAL chkdim(q)
1508 register Namep q;
1509 {
1510   register struct Dimblock *p;
1511   register int i;
1512   expptr e;
1513 
1514   if (q == NULL)
1515     return;
1516   if (q->vclass != CLVAR)
1517     return;
1518   if (q->vdim == NULL)
1519     return;
1520   p = q->vdim;
1521   for (i = 0; i < p->ndim; ++i)
1522     {
1523 #ifdef SDB
1524       if (sdbflag)
1525 	{
1526 	  if (e = p->dims[i].lb)
1527 	    chkdime(e, q);
1528 	  if (e = p->dims[i].ub)
1529 	    chkdime(e, q);
1530 	}
1531       else
1532 #endif SDB
1533       if (e = p->dims[i].dimexpr)
1534 	chkdime(e, q);
1535     }
1536 }
1537 
1538 
1539 
1540 /*
1541  * The actual checking for chkdim() -- examines each expression.
1542  */
1543 LOCAL chkdime(expr, q)
1544 expptr expr;
1545 Namep q;
1546 {
1547   register expptr e;
1548 
1549   e = fixtype(cpexpr(expr));
1550   if (!ISINT(e->exprblock.vtype))
1551     dclerr("non-integer dimension", q);
1552   else if (!safedim(e))
1553     dclerr("undefined dimension", q);
1554   frexpr(e);
1555   return;
1556 }
1557 
1558 
1559 
1560 /*
1561  * A recursive routine to find undefined variables in dimension expressions.
1562  */
1563 LOCAL safedim(e)
1564 expptr e;
1565 {
1566   chainp cp;
1567 
1568   if (e == NULL)
1569     return 1;
1570   switch (e->tag)
1571     {
1572       case TEXPR:
1573 	if (e->exprblock.opcode == OPCALL || e->exprblock.opcode == OPCCALL)
1574 	  return 0;
1575 	return safedim(e->exprblock.leftp) && safedim(e->exprblock.rightp);
1576       case TADDR:
1577 	switch (e->addrblock.vstg)
1578 	  {
1579 	    case STGCOMMON:
1580 	    case STGARG:
1581 	    case STGCONST:
1582 	    case STGEQUIV:
1583 	      if (e->addrblock.isarray)
1584 		return 0;
1585 	      return safedim(e->addrblock.memoffset);
1586 	    default:
1587 	      return 0;
1588 	  }
1589       case TCONST:
1590       case TTEMP:
1591 	return 1;
1592     }
1593   return 0;
1594 }
1595 
1596 
1597 
1598 LOCAL enlist(size, np, ep)
1599 ftnint size;
1600 Namep np;
1601 struct Equivblock *ep;
1602 {
1603   register sizelist *sp;
1604   register sizelist *t;
1605   register varlist *p;
1606 
1607   sp = varsizes;
1608 
1609   if (sp == NULL)
1610     {
1611       sp = ALLOC(SizeList);
1612       sp->size = size;
1613       varsizes = sp;
1614     }
1615   else
1616     {
1617       while (sp->size != size)
1618 	{
1619 	  if (sp->next != NULL && sp->next->size <= size)
1620 	    sp = sp->next;
1621 	  else
1622 	    {
1623 	      t = sp;
1624 	      sp = ALLOC(SizeList);
1625 	      sp->size = size;
1626 	      sp->next = t->next;
1627 	      t->next = sp;
1628 	    }
1629 	}
1630     }
1631 
1632   p = ALLOC(VarList);
1633   p->next = sp->vars;
1634   p->np = np;
1635   p->ep = ep;
1636 
1637   sp->vars = p;
1638 
1639   return;
1640 }
1641 
1642 
1643 
1644 outlocvars()
1645 {
1646 
1647   register varlist *first, *last;
1648   register varlist *vp, *t;
1649   register sizelist *sp, *sp1;
1650   register Namep np;
1651   register struct Equivblock *ep;
1652   register int i;
1653   register int alt;
1654   register int type;
1655   char sname[100];
1656   char setbuff[100];
1657 
1658   sp = varsizes;
1659   if (sp == NULL)
1660     return;
1661 
1662   vp = sp->vars;
1663   if (vp->np != NULL)
1664     {
1665       np = vp->np;
1666       sprintf(setbuff, "\t.set\tv.%d,v.%d\n", bsslabel,
1667 	      np->vardesc.varno);
1668     }
1669   else
1670     {
1671       i = vp->ep - eqvclass;
1672       sprintf(setbuff, "\t.set\tv.%d,q.%d\n", bsslabel, i + eqvstart);
1673     }
1674 
1675   first = last = NULL;
1676   alt = NO;
1677 
1678   while (sp != NULL)
1679     {
1680       vp = sp->vars;
1681       while (vp != NULL)
1682 	{
1683 	  t = vp->next;
1684 	  if (alt == YES)
1685 	    {
1686 	      alt = NO;
1687 	      vp->next = first;
1688 	      first = vp;
1689 	    }
1690 	  else
1691 	    {
1692 	      alt = YES;
1693 	      if (last != NULL)
1694 	        last->next = vp;
1695 	      else
1696 		first = vp;
1697 	      vp->next = NULL;
1698 	      last = vp;
1699 	    }
1700 	  vp = t;
1701 	}
1702       sp1 = sp;
1703       sp = sp->next;
1704       free((char *) sp1);
1705     }
1706 
1707   vp = first;
1708   while(vp != NULL)
1709     {
1710       if (vp->np != NULL)
1711 	{
1712 	  np = vp->np;
1713 	  sprintf(sname, "v.%d", np->vardesc.varno);
1714 	  pralign(typealign[np->vtype]);
1715 	  if (np->init)
1716 	    prlocdata(sname, np->varsize, np->vtype, np->initoffset,
1717 		      &(np->inlcomm));
1718 	  else
1719 	    {
1720 	      if (typealign[np->vtype] == 1)
1721 		  pralign(3);
1722 	      fprintf(initfile, "%s:\n\t.space\t%d\n", sname,
1723 		      np->varsize);
1724 	    }
1725 	  np->inlcomm = NO;
1726 	}
1727       else
1728 	{
1729 	  ep = vp->ep;
1730 	  i = ep - eqvclass;
1731 	  if (ep->eqvleng >= 8)
1732 	    type = TYDREAL;
1733 	  else if (ep->eqvleng >= 4)
1734 	    type = TYLONG;
1735 	  else if (ep->eqvleng >= 2)
1736 	    type = TYSHORT;
1737 	  else
1738 	    type = TYCHAR;
1739 	  sprintf(sname, "q.%d", i + eqvstart);
1740 	  if (ep->init)
1741 	    prlocdata(sname, ep->eqvleng, type, ep->initoffset,
1742 		      &(ep->inlcomm));
1743 	  else
1744 	    {
1745 	      pralign(typealign[type]);
1746 	      fprintf(initfile, "%s:\n\t.space\t%d\n", sname, ep->eqvleng);
1747 	    }
1748 	  ep->inlcomm = NO;
1749 	}
1750       t = vp;
1751       vp = vp->next;
1752       free((char *) t);
1753     }
1754   fprintf(initfile, "%s\n", setbuff);
1755   return;
1756 }
1757