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