372 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			372 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /****************************************************************
 | |
| Copyright 1990 by AT&T Bell Laboratories and Bellcore.
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this software
 | |
| and its documentation for any purpose and without fee is hereby
 | |
| granted, provided that the above copyright notice appear in all
 | |
| copies and that both that the copyright notice and this
 | |
| permission notice and warranty disclaimer appear in supporting
 | |
| documentation, and that the names of AT&T Bell Laboratories or
 | |
| Bellcore or any of their entities not be used in advertising or
 | |
| publicity pertaining to distribution of the software without
 | |
| specific, written prior permission.
 | |
| 
 | |
| AT&T and Bellcore disclaim all warranties with regard to this
 | |
| software, including all implied warranties of merchantability
 | |
| and fitness.  In no event shall AT&T or Bellcore be liable for
 | |
| any special, indirect or consequential damages or any damages
 | |
| whatsoever resulting from loss of use, data or profits, whether
 | |
| in an action of contract, negligence or other tortious action,
 | |
| arising out of or in connection with the use or performance of
 | |
| this software.
 | |
| ****************************************************************/
 | |
| 
 | |
| #include "defs.h"
 | |
| 
 | |
| LOCAL eqvcommon(), eqveqv(), nsubs();
 | |
| 
 | |
| /* ROUTINES RELATED TO EQUIVALENCE CLASS PROCESSING */
 | |
| 
 | |
| /* called at end of declarations section to process chains
 | |
|    created by EQUIVALENCE statements
 | |
|  */
 | |
| doequiv()
 | |
| {
 | |
| 	register int i;
 | |
| 	int inequiv;			/* True if one namep occurs in
 | |
| 					   several EQUIV declarations */
 | |
| 	int comno;		/* Index into Extsym table of the last
 | |
| 				   COMMON block seen (implicitly assuming
 | |
| 				   that only one will be given) */
 | |
| 	int ovarno;
 | |
| 	ftnint comoffset;	/* Index into the COMMON block */
 | |
| 	ftnint offset;		/* Offset from array base */
 | |
| 	ftnint leng;
 | |
| 	register struct Equivblock *equivdecl;
 | |
| 	register struct Eqvchain *q;
 | |
| 	struct Primblock *primp;
 | |
| 	register Namep np;
 | |
| 	int k, k1, ns, pref, t;
 | |
| 	chainp cp;
 | |
| 	extern int type_pref[];
 | |
| 
 | |
| 	for(i = 0 ; i < nequiv ; ++i)
 | |
| 	{
 | |
| 
 | |
| /* Handle each equivalence declaration */
 | |
| 
 | |
| 		equivdecl = &eqvclass[i];
 | |
| 		equivdecl->eqvbottom = equivdecl->eqvtop = 0;
 | |
| 		comno = -1;
 | |
| 
 | |
| 
 | |
| 
 | |
| 		for(q = equivdecl->equivs ; q ; q = q->eqvnextp)
 | |
| 		{
 | |
| 			offset = 0;
 | |
| 			primp = q->eqvitem.eqvlhs;
 | |
| 			vardcl(np = primp->namep);
 | |
| 			if(primp->argsp || primp->fcharp)
 | |
| 			{
 | |
| 				expptr offp, suboffset();
 | |
| 
 | |
| /* Pad ones onto the end of an array declaration when needed */
 | |
| 
 | |
| 				if(np->vdim!=NULL && np->vdim->ndim>1 &&
 | |
| 				    nsubs(primp->argsp)==1 )
 | |
| 				{
 | |
| 					if(! ftn66flag)
 | |
| 						warni
 | |
| 			("1-dim subscript in EQUIVALENCE, %d-dim declared",
 | |
| 						    np -> vdim -> ndim);
 | |
| 					cp = NULL;
 | |
| 					ns = np->vdim->ndim;
 | |
| 					while(--ns > 0)
 | |
| 						cp = mkchain((char *)ICON(1), cp);
 | |
| 					primp->argsp->listp->nextp = cp;
 | |
| 				}
 | |
| 
 | |
| 				offp = suboffset(primp);
 | |
| 				if(ISICON(offp))
 | |
| 					offset = offp->constblock.Const.ci;
 | |
| 				else	{
 | |
| 					dclerr
 | |
| 			("nonconstant subscript in equivalence ",
 | |
| 					    np);
 | |
| 					np = NULL;
 | |
| 				}
 | |
| 				frexpr(offp);
 | |
| 			}
 | |
| 
 | |
| /* Free up the primblock, since we now have a hash table (Namep) entry */
 | |
| 
 | |
| 			frexpr((expptr)primp);
 | |
| 
 | |
| 			if(np && (leng = iarrlen(np))<0)
 | |
| 			{
 | |
| 				dclerr("adjustable in equivalence", np);
 | |
| 				np = NULL;
 | |
| 			}
 | |
| 
 | |
| 			if(np) switch(np->vstg)
 | |
| 			{
 | |
| 			case STGUNKNOWN:
 | |
| 			case STGBSS:
 | |
| 			case STGEQUIV:
 | |
| 				break;
 | |
| 
 | |
| 			case STGCOMMON:
 | |
| 
 | |
| /* The code assumes that all COMMON references in a given EQUIVALENCE will
 | |
|    be to the same COMMON block, and will all be consistent */
 | |
| 
 | |
| 				comno = np->vardesc.varno;
 | |
| 				comoffset = np->voffset + offset;
 | |
| 				break;
 | |
| 
 | |
| 			default:
 | |
| 				dclerr("bad storage class in equivalence", np);
 | |
| 				np = NULL;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			if(np)
 | |
| 			{
 | |
| 				q->eqvoffset = offset;
 | |
| 
 | |
| /* eqvbottom   gets the largest difference between the array base address
 | |
|    and the address specified in the EQUIV declaration */
 | |
| 
 | |
| 				equivdecl->eqvbottom =
 | |
| 				    lmin(equivdecl->eqvbottom, -offset);
 | |
| 
 | |
| /* eqvtop   gets the largest difference between the end of the array and
 | |
|    the address given in the EQUIVALENCE */
 | |
| 
 | |
| 				equivdecl->eqvtop =
 | |
| 				    lmax(equivdecl->eqvtop, leng-offset);
 | |
| 			}
 | |
| 			q->eqvitem.eqvname = np;
 | |
| 		}
 | |
| 
 | |
| /* Now all equivalenced variables are in the hash table with the proper
 | |
|    offset, and   eqvtop and eqvbottom   are set. */
 | |
| 
 | |
| 		if(comno >= 0)
 | |
| 
 | |
| /* Get rid of all STGEQUIVS, they will be mapped onto STGCOMMON variables
 | |
|    */
 | |
| 
 | |
| 			eqvcommon(equivdecl, comno, comoffset);
 | |
| 		else for(q = equivdecl->equivs ; q ; q = q->eqvnextp)
 | |
| 		{
 | |
| 			if(np = q->eqvitem.eqvname)
 | |
| 			{
 | |
| 				inequiv = NO;
 | |
| 				if(np->vstg==STGEQUIV)
 | |
| 					if( (ovarno = np->vardesc.varno) == i)
 | |
| 					{
 | |
| 
 | |
| /* Can't EQUIV different elements of the same array */
 | |
| 
 | |
| 						if(np->voffset + q->eqvoffset != 0)
 | |
| 							dclerr
 | |
| 			("inconsistent equivalence", np);
 | |
| 					}
 | |
| 					else	{
 | |
| 						offset = np->voffset;
 | |
| 						inequiv = YES;
 | |
| 					}
 | |
| 
 | |
| 				np->vstg = STGEQUIV;
 | |
| 				np->vardesc.varno = i;
 | |
| 				np->voffset = - q->eqvoffset;
 | |
| 
 | |
| 				if(inequiv)
 | |
| 
 | |
| /* Combine 2 equivalence declarations */
 | |
| 
 | |
| 					eqveqv(i, ovarno, q->eqvoffset + offset);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| /* Now each equivalence declaration is distinct (all connections have been
 | |
|    merged in eqveqv()), and some may be empty. */
 | |
| 
 | |
| 	for(i = 0 ; i < nequiv ; ++i)
 | |
| 	{
 | |
| 		equivdecl = & eqvclass[i];
 | |
| 		if(equivdecl->eqvbottom!=0 || equivdecl->eqvtop!=0) {
 | |
| 
 | |
| /* a live chain */
 | |
| 
 | |
| 			k = TYCHAR;
 | |
| 			pref = 1;
 | |
| 			for(q = equivdecl->equivs ; q; q = q->eqvnextp)
 | |
| 			    if (np = q->eqvitem.eqvname){
 | |
| 				np->voffset -= equivdecl->eqvbottom;
 | |
| 				t = typealign[k1 = np->vtype];
 | |
| 				if (pref < type_pref[k1]) {
 | |
| 					k = k1;
 | |
| 					pref = type_pref[k1];
 | |
| 					}
 | |
| 				if(np->voffset % t != 0) {
 | |
| 					dclerr("bad alignment forced by equivalence", np);
 | |
| 					--nerr; /* don't give bad return code for this */
 | |
| 					}
 | |
| 				}
 | |
| 			equivdecl->eqvtype = k;
 | |
| 		}
 | |
| 		freqchain(equivdecl);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /* put equivalence chain p at common block comno + comoffset */
 | |
| 
 | |
| LOCAL eqvcommon(p, comno, comoffset)
 | |
| struct Equivblock *p;
 | |
| int comno;
 | |
| ftnint comoffset;
 | |
| {
 | |
| 	int ovarno;
 | |
| 	ftnint k, offq;
 | |
| 	register Namep np;
 | |
| 	register struct Eqvchain *q;
 | |
| 
 | |
| 	if(comoffset + p->eqvbottom < 0)
 | |
| 	{
 | |
| 		errstr("attempt to extend common %s backward",
 | |
| 		    extsymtab[comno].fextname);
 | |
| 		freqchain(p);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if( (k = comoffset + p->eqvtop) > extsymtab[comno].extleng)
 | |
| 		extsymtab[comno].extleng = k;
 | |
| 
 | |
| 
 | |
| 	for(q = p->equivs ; q ; q = q->eqvnextp)
 | |
| 		if(np = q->eqvitem.eqvname)
 | |
| 		{
 | |
| 			switch(np->vstg)
 | |
| 			{
 | |
| 			case STGUNKNOWN:
 | |
| 			case STGBSS:
 | |
| 				np->vstg = STGCOMMON;
 | |
| 				np->vcommequiv = 1;
 | |
| 				np->vardesc.varno = comno;
 | |
| 
 | |
| /* np -> voffset   will point to the base of the array */
 | |
| 
 | |
| 				np->voffset = comoffset - q->eqvoffset;
 | |
| 				break;
 | |
| 
 | |
| 			case STGEQUIV:
 | |
| 				ovarno = np->vardesc.varno;
 | |
| 
 | |
| /* offq   will point to the current element, even if it's in an array */
 | |
| 
 | |
| 				offq = comoffset - q->eqvoffset - np->voffset;
 | |
| 				np->vstg = STGCOMMON;
 | |
| 				np->vcommequiv = 1;
 | |
| 				np->vardesc.varno = comno;
 | |
| 
 | |
| /* np -> voffset   will point to the base of the array */
 | |
| 
 | |
| 				np->voffset += offq;
 | |
| 				if(ovarno != (p - eqvclass))
 | |
| 					eqvcommon(&eqvclass[ovarno], comno, offq);
 | |
| 				break;
 | |
| 
 | |
| 			case STGCOMMON:
 | |
| 				if(comno != np->vardesc.varno ||
 | |
| 				    comoffset != np->voffset+q->eqvoffset)
 | |
| 					dclerr("inconsistent common usage", np);
 | |
| 				break;
 | |
| 
 | |
| 
 | |
| 			default:
 | |
| 				badstg("eqvcommon", np->vstg);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	freqchain(p);
 | |
| 	p->eqvbottom = p->eqvtop = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Move all items on ovarno chain to the front of   nvarno   chain.
 | |
|  * adjust offsets of ovarno elements and top and bottom of nvarno chain
 | |
|  */
 | |
| 
 | |
| LOCAL eqveqv(nvarno, ovarno, delta)
 | |
| int ovarno, nvarno;
 | |
| ftnint delta;
 | |
| {
 | |
| 	register struct Equivblock *neweqv, *oldeqv;
 | |
| 	register Namep np;
 | |
| 	struct Eqvchain *q, *q1;
 | |
| 
 | |
| 	neweqv = eqvclass + nvarno;
 | |
| 	oldeqv = eqvclass + ovarno;
 | |
| 	neweqv->eqvbottom = lmin(neweqv->eqvbottom, oldeqv->eqvbottom - delta);
 | |
| 	neweqv->eqvtop = lmax(neweqv->eqvtop, oldeqv->eqvtop - delta);
 | |
| 	oldeqv->eqvbottom = oldeqv->eqvtop = 0;
 | |
| 
 | |
| 	for(q = oldeqv->equivs ; q ; q = q1)
 | |
| 	{
 | |
| 		q1 = q->eqvnextp;
 | |
| 		if( (np = q->eqvitem.eqvname) && np->vardesc.varno==ovarno)
 | |
| 		{
 | |
| 			q->eqvnextp = neweqv->equivs;
 | |
| 			neweqv->equivs = q;
 | |
| 			q->eqvoffset += delta;
 | |
| 			np->vardesc.varno = nvarno;
 | |
| 			np->voffset -= delta;
 | |
| 		}
 | |
| 		else	free( (charptr) q);
 | |
| 	}
 | |
| 	oldeqv->equivs = NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| freqchain(p)
 | |
| register struct Equivblock *p;
 | |
| {
 | |
| 	register struct Eqvchain *q, *oq;
 | |
| 
 | |
| 	for(q = p->equivs ; q ; q = oq)
 | |
| 	{
 | |
| 		oq = q->eqvnextp;
 | |
| 		free( (charptr) q);
 | |
| 	}
 | |
| 	p->equivs = NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /* nsubs -- number of subscripts in this arglist (just the length of the
 | |
|    list) */
 | |
| 
 | |
| LOCAL nsubs(p)
 | |
| register struct Listblock *p;
 | |
| {
 | |
| 	register int n;
 | |
| 	register chainp q;
 | |
| 
 | |
| 	n = 0;
 | |
| 	if(p)
 | |
| 		for(q = p->listp ; q ; q = q->nextp)
 | |
| 			++n;
 | |
| 
 | |
| 	return(n);
 | |
| }
 |