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

exlab(n)
register int n;
{
if(n==0 && thisexec->labelno && !(thisexec->labused))
	{
	thisexec->labused = 1;
	n = thisexec->labelno;
	}

if(!prevbg || n!=0)  /* avoid empty statement */
	{
	if(comments && !afterif) putcomment();
	putic(ICBEGIN, n);
	putic(ICINDENT, ctllevel);
	if(n != 0)
		if(stnos[n] != 0)
			fatal("statement number changed");
		else	stnos[n] = ( nxtstno += tailor.deltastno) ;
	TEST fprintf(diagfile, "LABEL %d\n", n);
	thisexec->nftnst++;
	afterif = 0;
	}
}


exgoto(n)
int n;
{
exlab(0);
exgo1(n);
}

exgoind(n)
int n;
{
exlab(0);
putic(ICKEYWORD,FGOTO);
putic(ICINDPTR,n);
TEST fprintf(diagfile, "goto indirect %o\n", n);
}



exgo1(n)
int n;
{
putic(ICKEYWORD,FGOTO);
putic(ICLABEL,n);
TEST fprintf(diagfile, "goto %d\n", n);
}


excompgoto(labs,index)
ptr labs;
register ptr index;
{
register int first;
register ptr p;

index = simple(LVAL,index);
if(tailor.ftn77)
	exlab(0);
else
	{
	int ncases = 0;
	for(p = labs ; p ; p = p->nextp)
		++ncases;
	exif1( mknode(TLOGOP, OPAND,
		mknode(TRELOP,OPGT, cpexpr(index), mkint(0)),
		mknode(TRELOP,OPLE, cpexpr(index), mkint(ncases)) ));
	}

putic(ICKEYWORD, FGOTO);
putic(ICOP,OPLPAR);

first = 1;
for(p = labs ; p ; p = p->nextp)
	{
	if(first)   first = 0;
	else   putic(ICOP,OPCOMMA);
	putic(ICLABEL,p->datap);
	}
putic(ICOP,OPRPAR);
frchain(&labs);

putic(ICOP,OPCOMMA);
prexpr(index);
frexpr(index);
TEST fprintf(diagfile, "computed goto\n");
}




excall(p)
register ptr p;
{
register ptr q1, q2, q3;
ptr mkholl(), exioop();

if(p->tag==TNAME || p->tag==TFTNBLOCK)
	p = mkcall(p, PNULL);

if(p->tag == TERROR)
	{
	frexpr(p);
	return;
	}
if(p->tag != TCALL)
	badtag("excall", p->tag);

q1 = p->leftp;
q2 = (q1->tag==TFTNBLOCK ? q1 : q1->sthead->varp);
if(q2->vtype!=TYUNDEFINED && q2->vtype!=TYSUBR)
	{
	dclerr("attempt to use a variable as a subroutine", p->sthead->namep);
	frexpr(p);
	return;
	}
q1->vtype = q2->vtype = TYSUBR;
if(q1->vdcldone==0)
	dclit(q1);

if(q1->tag == TNAME)
	{
	if( equals(q2->sthead->namep, "stop") )
		{
		exlab(0);
		putic(ICKEYWORD, FSTOP);
		TEST fprintf(diagfile,"stop ");
		if( (q1 = p->rightp) && (q1 = q1->leftp) )
			prexpr( simple(RVAL, q1->datap) );
		goto done;
		}
	if( ioop(q2->sthead->namep) )
		{
		exioop(p,NO);
		goto done;
		}
	}

p = simple(RVAL,p);
exlab(0);
putic(ICKEYWORD,FCALL);
TEST fprintf(diagfile, "call ");
/* replace character constant arguments with holleriths */
if( (q1=p->rightp) && tailor.hollincall)
	for(q1 = q1->leftp ; q1 ; q1 = q1->nextp)
		if( (q2 = q1->datap)->tag==TCONST
		    && q2->vtype==TYCHAR)
			{
			q2->vtype = TYHOLLERITH;
			frexpr(q2->vtypep);
			q2->vtypep = 0;
			q2->leftp = mkholl(q3 = q2->leftp);
			cfree(q3);
			}
prexpr( p );

done:	frexpr(p);
}




ptr mkholl(p)
register char *p;
{
register char *q, *t, *s;
int n;

n = strlen(p);
q = convic(n);
s = t = calloc(n + 2 + strlen(q) , 1);
while(*q)
	*t++ = *q++;
*t++ = 'h';
while(*t++ = *p++ )
	;
return(s);
}


ptr ifthen()
{
ptr p;
ptr addexec();

p = addexec();
thisexec->brnchend = 0;
if(thisexec->nftnst == 0)
	{
	exlab(0);
	putic(ICKEYWORD,FCONTINUE);
	thisexec->nftnst = 1;
	}
if(thisexec->nftnst>1 || thisexec->labeled || thisexec->uniffable )
	{
	if(thisctl->breaklab == 0)
		thisctl->breaklab = nextlab();
	indifs[thisctl->indifn] = thisctl->breaklab;
	}
else	thisctl->breaklab = 0;
return(p);
}



exasgn(l,o,r)
ptr l;
int o;
ptr r;
{
exlab(0);
if(l->vdcldone == 0)
	dclit(l);
frexpr( simple(LVAL , mknode(TASGNOP,o,l,r)) );
}

exretn(p)
ptr p;
{
if(p)
	{
	if(procname && procname->vtype && procname->vtype!=TYCHAR &&
	  (procname->vtype!=TYLCOMPLEX || tailor.lngcxtype!=NULL) )
		{
		if(p->tag!=TNAME || p->sthead!=procname->sthead)
			exasgn( cpexpr(procname) , OPASGN, p);
		}
	else execerr("can only return values in a function", PNULL);
	}
else if(procname && procname->vtype)
	 warn("function return without data value");
exlab(0);
putic(ICKEYWORD, FRETURN);

TEST {fprintf(diagfile, "exec: return( " );  prexpr(p);  fprintf(diagfile, ")\n" );  }
}


exnull()
{
if(thisexec->labelno && !(thisexec->labused) )
	{
	exlab(0);
	putic(ICKEYWORD,FCONTINUE);
	}
}




exbrk(opnext,levskip,btype)
int opnext;
ptr levskip;
int btype;
{

if(opnext && (btype==STSWITCH || btype==STPROC))
	execerr("illegal next", PNULL);
else if(!opnext && btype==STPROC)
	exretn(PNULL);
else  brknxtlab(opnext,levskip,btype);
TEST fprintf(diagfile, "exec: %s\n", (opnext ? "next" : "exit"));

}



exif(e)
register ptr e;
{
int tag;

if( (tag = e->tag)==TERROR || e->vtype!=TYLOG)
	{
	frexpr(e);
	e = mkconst(TYLOG, ".true.");
	if(tag != TERROR)
		execerr("non-logical conditional expression in if", PNULL);
	}
TEST fprintf(diagfile, "exif called\n");
e = simple(RVAL,e);
exlab(0);
putic(ICKEYWORD,FIF2);
indifs[thisctl->indifn = nextindif()] = 0;
putic(ICINDPTR, thisctl->indifn);
putic(ICOP,OPLPAR);
prexpr(e);
putic(ICOP,OPRPAR);
putic(ICMARK,0);
putic(ICOP,OPLPAR);
prexpr(e = simple(RVAL, mknode(TNOTOP,OPNOT,e,PNULL)));
putic(ICOP,OPRPAR);
putic(ICMARK,0);
afterif = 1;
frexpr(e);
}


exifgo(e,l)
ptr e;
int l;
{
exlab(0);
exif1(e);
exgo1(l);
}


exif1(e)
register ptr e;
{
e = simple(RVAL,e);
exlab(0);
putic(ICKEYWORD,FIF1);
putic(ICOP,OPLPAR);
TEST fprintf(diagfile, "if1 ");
prexpr( e );
frexpr(e);
putic(ICOP,OPRPAR);
putic(ICBLANK, 1);
}







brkcase()
{
ptr bgnexec();

if(ncases==0 /* && thisexec->prevexec->brnchend==0 */ )
	{
	exbrk(0, PNULL, 0);
	addexec();
	bgnexec();
	}
ncases = 1;
}


brknxtlab(opnext, levp, btype)
int opnext;
ptr levp;
int btype;
{
register ptr p;
int levskip;

levskip = ( levp ? convci(levp->leftp) : 1);
if(levskip <= 0)
	{
	execerr("illegal break count %d", levskip);
	return;
	}

for(p = thisctl ; p!=0 ; p = p->prevctl)
	if( (btype==0 || p->subtype==btype) &&
	    p->subtype!=STIF && p->subtype!=STPROC &&
	    (!opnext || p->subtype!=STSWITCH) )
		if(--levskip == 0) break;

if(p == 0)
	{
	execerr("invalid break/next", PNULL);
	return;
	}

if(p->subtype==STREPEAT && opnext)
	exgoind(p->indifn);
else if(opnext)
	exgoto(p->nextlab);
else	{
	if(p->breaklab == 0)
		p->breaklab = nextlab();
	exgoto(p->breaklab);
	}
}



ptr doloop(p1,p2,p3)
ptr p1;
ptr p2;
ptr p3;
{
register ptr p, q;
register int i;
int val[3];

p = ALLOC(doblock);
p->tag = TDOBLOCK;

if(p1->tag!=TASGNOP || p1->subtype!=OPASGN || p1->leftp->tag!=TNAME)
	{
	p->dovar = gent(TYINT, PNULL);
	p->dopar[0] = p1;
	}
else	{
	p->dovar = p1->leftp;
	p->dopar[0] = p1->rightp;
	frexpblock(p1);
	}
if(p2 == 0)
	{
	p->dopar[1] = p->dopar[0];
	p->dopar[0] = mkint(1);
	}
else	p->dopar[1] = p2;
p->dopar[2] = p3;

for(i = 0; i<3 ; ++i)
	{
	if(q = p->dopar[i])
		{
		if( (q->tag==TNAME || q->tag==TTEMP) &&
		   (q->vsubs || q->voffset) )
			p->dopar[i] = simple(RVAL,mknode(TASGNOP,0,
				gent(TYINT,PNULL), q));
		else
			p->dopar[i] = simple(LVAL, coerce(TYINT, q) );

		if(isicon(p->dopar[i], &val[i]))
			{
			if(val[i] <= 0)
				execerr("do parameter out of range", PNULL);
			}
		else	val[i] = -1;
		}
	}

if(val[0]>0 && val[1]>0 && val[0]>val[1])
	execerr("do parameters out of order", PNULL);
return(p);
}
