/*	@(#)struct.c	2.1		*/
/*	3.0 SID #	1.2	*/
#include "defs"

offsets(s)
register ptr s;
{
register ptr p, q;
ptr t;
ptr prevp;
int n;
int size, align, mask, nelt;
double rshift;

s->stralign = 1;
s->strsize = 0;
s->basetypes = 0;
prevp = 0;
rshift = 0;

for(p = s->strdesc ; p ; p = p->nextp)
	{
	q = p->datap;
	if(q->vclass != 0)
		dclerr("attempt to give storage class to mos",
			q->namep);
	else  q->vclass = CLMOS;
	if(q->vtype == TYUNDEFINED)
		impldecl(q);

	sizalign(q, &size, &align, &mask);
	s->strsize = evenoff(s->strsize, align);
	q->voffset = mkint(s->strsize);
	/* sloppy formula */
	nelt = 1;
	if(t = q->vdim)
	    for(t = t->datap ; t ; t = t->nextp)
		{
		if(t->upperb == 0) continue;
		n = conval(t->upperb);
		if(t->lowerb)
			n -= conval(t->lowerb)-1;
		nelt *= n;
		}
	if(q->vtype==TYFIELD && q->vdim==0 &&
	     (n=conval(q->vtypep->frange))*rshift<=fieldmax && rshift>0)
		{
		prevp->vtypep->fanymore = 1;
		q->vtypep->frshift = mkint( (int) rshift );
		rshift *= n;
		cfree(q->voffset);
		q->voffset = mkint(s->strsize - tailor.ftnsize[FTNINT]);
		}
	else	{
		if(q->vdim!=0 && q->vtype==TYFIELD)
			q->vtype = TYINT;
		rshift = (q->vtype==TYFIELD ? n : 0);
		s->strsize +=  nelt * evenoff(size,align);
		s->stralign = lcm(s->stralign, align);
		s->basetypes |= mask;
		}
	prevp = q;
	}
}


lcm(a,b)
int a,b;
{
int ab, c;

if( (ab = a*b) == 0) return(0);

while(b)
	{
	c = a%b;
	a = b;
	b = c;
	}

return(ab/a);
}





sizalign(p, s, a, m)
register ptr p;
int *s;
int *a;
int *m;
{
register int k, t;

if(p->tag == TERROR)
	return;
if(p->tag!=TNAME && p->tag!=TTEMP && p->tag!=TFTNBLOCK)
	badtag("sizalign", p->tag);
switch(t = p->vtype)
	{
	case TYFIELD:
	case TYINT:
	case TYREAL:
	case TYLREAL:
	case TYCOMPLEX:
	case TYLOG:
		k = eflftn[t];
		*s = tailor.ftnsize[k];
		*a = tailor.ftnalign[k];
		*m = ftnmask[k];
		return;

	case TYLCOMPLEX:
		if(tailor.lngcxtype)
			{
			k = FTNDCOMPLEX;
			*s = tailor.ftnsize[FTNDCOMPLEX];
			}
		else
			{
			k = FTNDOUBLE;
			*s = 2*tailor.ftnsize[k];
			}
		*a = tailor.ftnalign[k];
		*m = ftnmask[k];
		return;

	case TYSTRUCT:
		*s = p->vtypep->strsize;
		*a = p->vtypep->stralign;
		*m = p->vtypep->basetypes;
		return;

	case TYCHAR:
		*s = tailor.ftnsize[FTNINT] *
			ceil(conval(p->vtypep), tailor.ftnchwd);
		*a = tailor.ftnalign[FTNINT];
		*m = ftnmask[FTNINT];
		return;

	case TYSUBR:
		*s = 1;
		*a = 1;
		*m = 1;
		dclerr("subroutine name as variable", p->sthead->namep);
		return;

	default:
		fatal1("sizalign: invalid type %d", t);
	}
}



evenoff(a,b)	/* round a up to a multiple of b */
int a,b;
{
return(b * ceil(a,b));
}


ceil(a,b)
int a,b;
{
return( (a+b-1)/b );
}




ptr esizeof(type, typep, dim)
register int type;
register ptr typep;
ptr dim;
{
register int k;

switch(type)
	{
	case TYFIELD:
	case TYINT:
	case TYREAL:
	case TYLREAL:
	case TYCOMPLEX:
	case TYLCOMPLEX:
	case TYLOG:
		k = tailor.ftnsize[ eflftn[type] ];
		break;

	case TYSTRUCT:
		k = typep->strsize;
		break;

	case TYCHAR:
		k = tailor.ftnsize[FTNINT] * ceil(conval(typep), tailor.ftnchwd);
		break;

	default:
		exprerr("invalid sizeof", "");
		k = 0;
	}
/* debug version.  should multiply by dimension */
return( mkint(k) );
}



ptr elenof(type, typep, dim)
register int type;
register ptr typep;
ptr dim;
{
if(type == TYCHAR)
	return( mkint( conval(typep) ) );
exprerr("invalid lengthof", "");
return( mkint(0) );
/* debug version.  should multiply by dimension */
}
