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