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