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



ptr mkfield(q)
register ptr q;
{
register ptr p;

if(!instruct)
	goto err;
else if(q->upperb == 0)
	dclerr("must have upper bound in field spcification", "");
else
	{
	p = ALLOC(fieldspec);
	p->tag = TFIELD;
	if(q->lowerb)
		{
		p->flbound = q->lowerb;
		p->frange = mknode(TAROP,OPPLUS,mknode(TAROP,OPMINUS,
				q->upperb, cpexpr(q->lowerb)),
				mkconst(TYINT,"1") );
		}
	else	{
		p->flbound = mkconst(TYINT,"1");
		p->frange = q->upperb;
		}
	p->frange = simple(RVAL,p->frange);
	if(p->frange->tag != TCONST)
		{
		dclerr("field range must be constant", "");
		cfree(p);
		goto err;
		}
	cfree(q);
	return(p);
	}

err:
	cfree(q);
	return( errnode() );
}





ptr extrfield(p)
register ptr p;
{
register ptr t;

t = p->vtypep;
p->vtype = TYINT;
p->vtypep = 0;

if(t->frshift)
	p = mknode(TAROP,OPSLASH, p, cpexpr(t->frshift));
if(t->fanymore)
	p = mkcall(builtin(TYINT, "mod"), arg2(p, cpexpr(t->frange)) );
p = mknode(TAROP,OPPLUS, p, cpexpr(t->flbound));
return(p);
}




ptr setfield(e)
ptr e;
{
ptr lp, rp;
register ptr f, p;
int subt;

lp = cpexpr(e->leftp);
rp = e->rightp;
subt = e->subtype;
f = lp->vtypep;
lp->vtype = TYINT;
lp->vtypep = 0;

if(subt==OPPLUS || subt==OPMINUS)
	{
	if(f->frshift)
		rp = mknode(TAROP,OPSTAR,rp,cpexpr(f->frshift));
	}
else	{
	if(subt != OPASGN)
		{
		rp = mknode(TAROP,subt, extrfield(cpexpr(e->leftp)), rp);
		subt = OPASGN;
		}
	rp = coerce(TYINT,rp);
	if(f->flbound)
		rp = simple(RVAL, mknode(TAROP,OPMINUS,rp,cpexpr(f->flbound)) );
	
	if(f->frshift==0)
		{
		if(f->fanymore)
			{
			p = mknode(TAROP,OPSLASH,cpexpr(lp),cpexpr(f->frange));
			p->needpar = YES;
			p = mknode(TAROP,OPSTAR,cpexpr(f->frange),p);
			rp = mknode(TAROP,OPPLUS,p,rp);
			}
		}
	else if(f->fanymore==0)
		{
		rp = mknode(TAROP,OPSTAR,cpexpr(f->frshift),rp);
		p = mkcall(builtin(TYINT,"mod"),
			arg2(cpexpr(lp),cpexpr(f->frshift)) );
		rp = mknode(TAROP,OPPLUS, p,rp);
		}
	else	{
		p = mknode(TAROP,OPSLASH,cpexpr(lp),cpexpr(f->frshift));
		p = mkcall(builtin(TYINT,"mod"), 
			arg2(p, cpexpr(f->frange)) );
		if( rp->tag!=TCONST || !equals(rp->leftp, "0") )
			p = mknode(TAROP,OPMINUS, p, rp);
		rp = mknode(TAROP,OPSTAR, cpexpr(f->frshift), p);
		rp = mknode(TAROP,OPMINUS, cpexpr(lp), rp);
		}
	}
frexpr( simple(LVAL, mknode(TASGNOP,subt,lp,rp) ));
return(extrfield(e->leftp));
}
