#include "defs"
#include "string_defs"

/* ROUTINES CALLED DURING DATA STATEMENT PROCESSING */

static char *datafmt = "%s\t%05ld\t%05ld\t%d" ;

/* another initializer, called from parser */
dataval(repp, valp)
register struct constblock *repp, *valp;
{
int i, nrep;
ftnint elen, vlen;
register struct addrblock *p;
struct addrblock *nextdata();

if(repp == NULL)
	nrep = 1;
else if (ISICON(repp) && repp->const.ci >= 0)
	nrep = repp->const.ci;
else
	{
	error("invalid repetition count in DATA statement",0,0,ERR);
	frexpr(repp);
	goto ret;
	}
frexpr(repp);

if( ! ISCONST(valp) )
	{
	error("nonconstant initializer",0,0,ERR);
	goto ret;
	}

if(toomanyinit) goto ret;
for(i = 0 ; i < nrep ; ++i)
	{
	p = nextdata(&elen, &vlen);
	if(p == NULL)
		{
		error("too many initializers",0,0,ERR);
		toomanyinit = YES;
		goto ret;
		}
	setdata(p, valp, elen, vlen);
	frexpr(p);
	}

ret:
	frexpr(valp);
}


struct addrblock *nextdata(elenp, vlenp)
ftnint *elenp, *vlenp;
{
register struct impldoblock *ip;
struct primblock *pp;
register struct nameblock *np;
register struct rplblock *rp;
tagptr p;
expptr neltp;
register expptr q;
int skip;
ftnint off;
struct constblock *mkintcon();

while(curdtp)
	{
	p = curdtp->datap;
	if(p->tag == TIMPLDO)
		{
		ip = p;
		if(ip->implb==NULL || ip->impub==NULL || ip->varnp==NULL)
			error("bad impldoblock 0%o", ip,0,FATAL1);
		if(ip->isactive)
			ip->varvp->const.ci += ip->impdiff;
		else
			{
			q = fixtype(cpexpr(ip->implb));
			if( ! ISICON(q) )
				goto doerr;
			ip->varvp = q;

			if(ip->impstep)
				{
				q = fixtype(cpexpr(ip->impstep));
				if( ! ISICON(q) )
					goto doerr;
				ip->impdiff = q->const.ci;
				frexpr(q);
				}
			else
				ip->impdiff = 1;

			q = fixtype(cpexpr(ip->impub));
			if(! ISICON(q))
				goto doerr;
			ip->implim = q->const.ci;
			frexpr(q);

			ip->isactive = YES;
			rp = ALLOC(rplblock);
			rp->nextp = rpllist;
			rpllist = rp;
			rp->rplnp = ip->varnp;
			rp->rplvp = ip->varvp;
			rp->rpltag = TCONST;
			}

		if( (ip->impdiff>0 && (ip->varvp->const.ci <= ip->implim))
		 || (ip->impdiff<0 && (ip->varvp->const.ci >= ip->implim)) )
			{ /* start new loop */
			curdtp = ip->datalist;
			goto next;
			}

		/* clean up loop */

		popstack(&rpllist);

		frexpr(ip->varvp);
		ip->isactive = NO;
		curdtp = curdtp->nextp;
		goto next;
		}

	pp = p;
	np = pp->namep;
	skip = YES;

	if(p->argsp==NULL && np->vdim!=NULL)
		{   /* array initialization */
		q = mkaddr(np);
		off = typesize[np->vtype] * curdtelt;
		if(np->vtype == TYCHAR)
			off *= np->vleng->const.ci;
		q->memoffset = mkexpr(OPPLUS, q->memoffset, mkintcon(off) );
		if( (neltp = np->vdim->nelt) && ISCONST(neltp))
			{
			if(++curdtelt < neltp->const.ci)
				skip = NO;
			}
		else
			error("attempt to initialize adjustable array",0,0,ERR);
		}
	else
		q = mklhs( cpexpr(pp) );
	if(skip)
		{
		curdtp = curdtp->nextp;
		curdtelt = 0;
		}
	if(q->vtype == TYCHAR)
		if(ISICON(q->vleng))
			*elenp = q->vleng->const.ci;
		else	{
			error("initialization of string of nonconstant length",0,0,ERR);
			continue;
			}
	else	*elenp = typesize[q->vtype];

	if(np->vstg == STGCOMMON)
		*vlenp = extsymtab[np->vardesc.varno].maxleng;
	else if(np->vstg == STGEQUIV)
		*vlenp = eqvclass[np->vardesc.varno].eqvleng;
	else	{
		*vlenp =  (np->vtype==TYCHAR ?
				np->vleng->const.ci : typesize[np->vtype]);
		if(np->vdim)
			*vlenp *= np->vdim->nelt->const.ci;
		}
	return(q);

doerr:
		error("nonconstant implied DO parameter",0,0,ERR);
		frexpr(q);
		curdtp = curdtp->nextp;

next:	curdtelt = 0;
	}

return(NULL);
}






LOCAL setdata(varp, valp, elen, vlen)
struct addrblock *varp;
ftnint elen, vlen;
struct constblock *valp;
{
union constant con;
int i, k;
int stg, type, valtype;
ftnint offset;
register char *s, *t;
char *memname();
static char varname[XL+2];

/* output form of name is padded with blanks and preceded
   with a storage class digit
*/

stg = varp->vstg;
varname[0] = (stg==STGCOMMON ? '2' : (stg==STGEQUIV ? '1' : '0') );
s = memname(stg, varp->memno);
for(t = varname+1 ; *s ; )
	*t++ = *s++;
while(t < varname+XL+1)
	*t++ = ' ';
varname[XL+1] = '\0';

offset = varp->memoffset->const.ci;
type = varp->vtype;
valtype = valp->vtype;
if(type!=TYCHAR && valtype==TYCHAR)
	{
	if(! ftn66flag)
		error("noncharacter type initialized with string",0,0,WARN);
	varp->vleng = ICON(typesize[type]);
	varp->vtype = type = TYCHAR;
	}
else if( (type==TYCHAR && valtype!=TYCHAR) ||
	 (cktype(OPASSIGN,type,valtype) == TYERROR) )
	{
	error("incompatible types in initialization",0,0,ERR);
	return;
	}
if(type != TYCHAR)
	if(valtype == TYUNKNOWN)
		con.ci = valp->const.ci;
	else	consconv(type, &con, valtype, &valp->const);

k = 1;
switch(type)
	{
	case TYLOGICAL:
		type = tylogical;
	case TYSHORT:
	case TYLONG:
		fprintf(initfile, datafmt, varname, offset, vlen, type);
		prconi(initfile, type, con.ci);
		break;

	case TYCOMPLEX:
		k = 2;
		type = TYREAL;
	case TYREAL:
		goto flpt;

	case TYDCOMPLEX:
		k = 2;
		type = TYDREAL;
	case TYDREAL:
	flpt:

		for(i = 0 ; i < k ; ++i)
			{
			fprintf(initfile, datafmt, varname, offset, vlen, type);
			prconr(initfile, type, con.cd[i]);
			offset += typesize[type];
			}
		break;

	case TYCHAR:
		k = valp->vleng->const.ci;
		if(elen < k)
			k = elen;

		for(i = 0 ; i < k ; ++i)
			{
			fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR);
			fprintf(initfile, "\t%d\n", valp->const.ccp[i]);
			}
		k = elen - valp->vleng->const.ci;
		while( k-- > 0)
			{
			fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR);
			fprintf(initfile, "\t%d\n", ' ');
			}
		break;

	default:
		error("setdata: impossible type %d", type,0,FATAL1);
	}

}



frdata(p0)
chainp p0;
{
register chainp p;
register tagptr q;

for(p = p0 ; p ; p = p->nextp)
	{
	q = p->datap;
	if(q->tag == TIMPLDO)
		{
		if(q->isbusy)
			return;	/* circular chain completed */
		q->isbusy = YES;
		frdata(q->datalist);
		free(q);
		}
	else
		frexpr(q);
	}

frchain( &p0);
}
