831 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			831 lines
		
	
	
	
		
			18 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"
 | 
						|
#include "p1defs.h"
 | 
						|
#include "names.h"
 | 
						|
 | 
						|
LOCAL void exar2(), popctl(), pushctl();
 | 
						|
 | 
						|
/*   Logical IF codes
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
exif(p)
 | 
						|
expptr p;
 | 
						|
{
 | 
						|
    pushctl(CTLIF);
 | 
						|
    putif(p, 0);	/* 0 => if, not elseif */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
exelif(p)
 | 
						|
expptr p;
 | 
						|
{
 | 
						|
    if (ctlstack->ctltype == CTLIF || ctlstack->ctltype == CTLIFX)
 | 
						|
	putif(p, 1);	/* 1 ==> elseif */
 | 
						|
    else
 | 
						|
	execerr("elseif out of place", CNULL);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
exelse()
 | 
						|
{
 | 
						|
	register struct Ctlframe *c;
 | 
						|
 | 
						|
	for(c = ctlstack; c->ctltype == CTLIFX; --c);
 | 
						|
	if(c->ctltype == CTLIF) {
 | 
						|
		p1_else ();
 | 
						|
		c->ctltype = CTLELSE;
 | 
						|
		}
 | 
						|
	else
 | 
						|
		execerr("else out of place", CNULL);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
exendif()
 | 
						|
{
 | 
						|
	while(ctlstack->ctltype == CTLIFX) {
 | 
						|
		popctl();
 | 
						|
		p1else_end();
 | 
						|
		}
 | 
						|
	if(ctlstack->ctltype == CTLIF) {
 | 
						|
		popctl();
 | 
						|
		p1_endif ();
 | 
						|
		}
 | 
						|
	else if(ctlstack->ctltype == CTLELSE) {
 | 
						|
		popctl();
 | 
						|
		p1else_end ();
 | 
						|
		}
 | 
						|
	else
 | 
						|
		execerr("endif out of place", CNULL);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
new_endif()
 | 
						|
{
 | 
						|
	if (ctlstack->ctltype == CTLIF || ctlstack->ctltype == CTLIFX)
 | 
						|
		pushctl(CTLIFX);
 | 
						|
	else
 | 
						|
		err("new_endif bug");
 | 
						|
	}
 | 
						|
 | 
						|
/* pushctl -- Start a new control construct, initialize the labels (to
 | 
						|
   zero) */
 | 
						|
 | 
						|
 LOCAL void
 | 
						|
pushctl(code)
 | 
						|
 int code;
 | 
						|
{
 | 
						|
	register int i;
 | 
						|
 | 
						|
	if(++ctlstack >= lastctl)
 | 
						|
		many("loops or if-then-elses", 'c', maxctl);
 | 
						|
	ctlstack->ctltype = code;
 | 
						|
	for(i = 0 ; i < 4 ; ++i)
 | 
						|
		ctlstack->ctlabels[i] = 0;
 | 
						|
	ctlstack->dowhile = 0;
 | 
						|
	++blklevel;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 LOCAL void
 | 
						|
popctl()
 | 
						|
{
 | 
						|
	if( ctlstack-- < ctls )
 | 
						|
		Fatal("control stack empty");
 | 
						|
	--blklevel;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* poplab -- update the flags in   labeltab   */
 | 
						|
 | 
						|
LOCAL poplab()
 | 
						|
{
 | 
						|
	register struct Labelblock  *lp;
 | 
						|
 | 
						|
	for(lp = labeltab ; lp < highlabtab ; ++lp)
 | 
						|
		if(lp->labdefined)
 | 
						|
		{
 | 
						|
			/* mark all labels in inner blocks unreachable */
 | 
						|
			if(lp->blklevel > blklevel)
 | 
						|
				lp->labinacc = YES;
 | 
						|
		}
 | 
						|
		else if(lp->blklevel > blklevel)
 | 
						|
		{
 | 
						|
			/* move all labels referred to in inner blocks out a level */
 | 
						|
			lp->blklevel = blklevel;
 | 
						|
		}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*  BRANCHING CODE
 | 
						|
*/
 | 
						|
 | 
						|
exgoto(lab)
 | 
						|
struct Labelblock *lab;
 | 
						|
{
 | 
						|
	lab->labused = 1;
 | 
						|
	p1_goto (lab -> stateno);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
exequals(lp, rp)
 | 
						|
register struct Primblock *lp;
 | 
						|
register expptr rp;
 | 
						|
{
 | 
						|
	if(lp->tag != TPRIM)
 | 
						|
	{
 | 
						|
		err("assignment to a non-variable");
 | 
						|
		frexpr((expptr)lp);
 | 
						|
		frexpr(rp);
 | 
						|
	}
 | 
						|
	else if(lp->namep->vclass!=CLVAR && lp->argsp)
 | 
						|
	{
 | 
						|
		if(parstate >= INEXEC)
 | 
						|
			err("statement function amid executables");
 | 
						|
		mkstfunct(lp, rp);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		expptr new_lp, new_rp;
 | 
						|
 | 
						|
		if(parstate < INDATA)
 | 
						|
			enddcl();
 | 
						|
		new_lp = mklhs (lp);
 | 
						|
		new_rp = fixtype (rp);
 | 
						|
		puteq(new_lp, new_rp);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* Make Statement Function */
 | 
						|
 | 
						|
long laststfcn = -1, thisstno;
 | 
						|
int doing_stmtfcn;
 | 
						|
 | 
						|
mkstfunct(lp, rp)
 | 
						|
struct Primblock *lp;
 | 
						|
expptr rp;
 | 
						|
{
 | 
						|
	register struct Primblock *p;
 | 
						|
	register Namep np;
 | 
						|
	chainp args;
 | 
						|
 | 
						|
	laststfcn = thisstno;
 | 
						|
	np = lp->namep;
 | 
						|
	if(np->vclass == CLUNKNOWN)
 | 
						|
		np->vclass = CLPROC;
 | 
						|
	else
 | 
						|
	{
 | 
						|
		dclerr("redeclaration of statement function", np);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	np->vprocclass = PSTFUNCT;
 | 
						|
	np->vstg = STGSTFUNCT;
 | 
						|
 | 
						|
/* Set the type of the function */
 | 
						|
 | 
						|
	impldcl(np);
 | 
						|
	if (np->vtype == TYCHAR && !np->vleng)
 | 
						|
		err("character statement function with length (*)");
 | 
						|
	args = (lp->argsp ? lp->argsp->listp : CHNULL);
 | 
						|
	np->varxptr.vstfdesc = mkchain((char *)args, (chainp)rp);
 | 
						|
 | 
						|
	for(doing_stmtfcn = 1 ; args ; args = args->nextp)
 | 
						|
 | 
						|
/* It is an error for the formal parameters to have arguments or
 | 
						|
   subscripts */
 | 
						|
 | 
						|
		if( ((tagptr)(args->datap))->tag!=TPRIM ||
 | 
						|
		    (p = (struct Primblock *)(args->datap) )->argsp ||
 | 
						|
		    p->fcharp || p->lcharp )
 | 
						|
			err("non-variable argument in statement function definition");
 | 
						|
		else
 | 
						|
		{
 | 
						|
 | 
						|
/* Replace the name on the left-hand side */
 | 
						|
 | 
						|
			args->datap = (char *)p->namep;
 | 
						|
			vardcl(p -> namep);
 | 
						|
			free((char *)p);
 | 
						|
		}
 | 
						|
	doing_stmtfcn = 0;
 | 
						|
}
 | 
						|
 | 
						|
 static void
 | 
						|
mixed_type(np)
 | 
						|
 Namep np;
 | 
						|
{
 | 
						|
	char buf[128];
 | 
						|
	sprintf(buf, "%s function %.90s invoked as subroutine",
 | 
						|
		ftn_types[np->vtype], np->fvarname);
 | 
						|
	warn(buf);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
excall(name, args, nstars, labels)
 | 
						|
Namep name;
 | 
						|
struct Listblock *args;
 | 
						|
int nstars;
 | 
						|
struct Labelblock *labels[ ];
 | 
						|
{
 | 
						|
	register expptr p;
 | 
						|
 | 
						|
	if (name->vtype != TYSUBR) {
 | 
						|
		if (name->vinfproc && !name->vcalled) {
 | 
						|
			name->vtype = TYSUBR;
 | 
						|
			frexpr(name->vleng);
 | 
						|
			name->vleng = 0;
 | 
						|
			}
 | 
						|
		else if (!name->vimpltype && name->vtype != TYUNKNOWN)
 | 
						|
			mixed_type(name);
 | 
						|
		else
 | 
						|
			settype(name, TYSUBR, (ftnint)0);
 | 
						|
		}
 | 
						|
	p = mkfunct( mkprim(name, args, CHNULL) );
 | 
						|
 | 
						|
/* Subroutines and their identifiers acquire the type INT */
 | 
						|
 | 
						|
	p->exprblock.vtype = p->exprblock.leftp->headblock.vtype = TYINT;
 | 
						|
 | 
						|
/* Handle the alternate return mechanism */
 | 
						|
 | 
						|
	if(nstars > 0)
 | 
						|
		putcmgo(putx(fixtype(p)), nstars, labels);
 | 
						|
	else
 | 
						|
		putexpr(p);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
exstop(stop, p)
 | 
						|
int stop;
 | 
						|
register expptr p;
 | 
						|
{
 | 
						|
	char *str;
 | 
						|
	int n;
 | 
						|
	expptr mkstrcon();
 | 
						|
 | 
						|
	if(p)
 | 
						|
	{
 | 
						|
		if( ! ISCONST(p) )
 | 
						|
		{
 | 
						|
			execerr("pause/stop argument must be constant", CNULL);
 | 
						|
			frexpr(p);
 | 
						|
			p = mkstrcon(0, CNULL);
 | 
						|
		}
 | 
						|
		else if( ISINT(p->constblock.vtype) )
 | 
						|
		{
 | 
						|
			str = convic(p->constblock.Const.ci);
 | 
						|
			n = strlen(str);
 | 
						|
			if(n > 0)
 | 
						|
			{
 | 
						|
				p->constblock.Const.ccp = copyn(n, str);
 | 
						|
				p->constblock.Const.ccp1.blanks = 0;
 | 
						|
				p->constblock.vtype = TYCHAR;
 | 
						|
				p->constblock.vleng = (expptr) ICON(n);
 | 
						|
			}
 | 
						|
			else
 | 
						|
				p = (expptr) mkstrcon(0, CNULL);
 | 
						|
		}
 | 
						|
		else if(p->constblock.vtype != TYCHAR)
 | 
						|
		{
 | 
						|
			execerr("pause/stop argument must be integer or string", CNULL);
 | 
						|
			p = (expptr) mkstrcon(0, CNULL);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else	p = (expptr) mkstrcon(0, CNULL);
 | 
						|
 | 
						|
    {
 | 
						|
	expptr subr_call;
 | 
						|
 | 
						|
	subr_call = call1(TYSUBR, (stop ? "s_stop" : "s_paus"), p);
 | 
						|
	putexpr( subr_call );
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* DO LOOP CODE */
 | 
						|
 | 
						|
#define DOINIT	par[0]
 | 
						|
#define DOLIMIT	par[1]
 | 
						|
#define DOINCR	par[2]
 | 
						|
 | 
						|
 | 
						|
/* Macros for   ctlstack -> dostepsign   */
 | 
						|
 | 
						|
#define VARSTEP	0
 | 
						|
#define POSSTEP	1
 | 
						|
#define NEGSTEP	2
 | 
						|
 | 
						|
 | 
						|
/* exdo -- generate DO loop code.  In the case of a variable increment,
 | 
						|
   positive increment tests are placed above the body, negative increment
 | 
						|
   tests are placed below (see   enddo()   ) */
 | 
						|
 | 
						|
exdo(range, loopname, spec)
 | 
						|
int range;			/* end label */
 | 
						|
Namep loopname;
 | 
						|
chainp spec;			/* input spec must have at least 2 exprs */
 | 
						|
{
 | 
						|
	register expptr p;
 | 
						|
	register Namep np;
 | 
						|
	chainp cp;		/* loops over the fields in   spec */
 | 
						|
	register int i;
 | 
						|
	int dotype;		/* type of the index variable */
 | 
						|
	int incsign;		/* sign of the increment, if it's constant
 | 
						|
				   */
 | 
						|
	Addrp dovarp;		/* loop index variable */
 | 
						|
	expptr doinit;		/* constant or register for init param */
 | 
						|
	expptr par[3];		/* local specification parameters */
 | 
						|
 | 
						|
	expptr init, test, inc;	/* Expressions in the resulting FOR loop */
 | 
						|
 | 
						|
 | 
						|
	test = ENULL;
 | 
						|
 | 
						|
	pushctl(CTLDO);
 | 
						|
	dorange = ctlstack->dolabel = range;
 | 
						|
	ctlstack->loopname = loopname;
 | 
						|
 | 
						|
/* Declare the loop index */
 | 
						|
 | 
						|
	np = (Namep)spec->datap;
 | 
						|
	ctlstack->donamep = NULL;
 | 
						|
	if (!np) { /* do while */
 | 
						|
		ctlstack->dowhile = 1;
 | 
						|
#if 0
 | 
						|
		if (loopname) {
 | 
						|
			if (loopname->vtype == TYUNKNOWN) {
 | 
						|
				loopname->vdcldone = 1;
 | 
						|
				loopname->vclass = CLLABEL;
 | 
						|
				loopname->vprocclass = PLABEL;
 | 
						|
				loopname->vtype = TYLABEL;
 | 
						|
				}
 | 
						|
			if (loopname->vtype == TYLABEL)
 | 
						|
				if (loopname->vdovar)
 | 
						|
					dclerr("already in use as a loop name",
 | 
						|
						loopname);
 | 
						|
				else
 | 
						|
					loopname->vdovar = 1;
 | 
						|
			else
 | 
						|
				dclerr("already declared; cannot be a loop name",
 | 
						|
					loopname);
 | 
						|
			}
 | 
						|
#endif
 | 
						|
		putwhile((expptr)spec->nextp);
 | 
						|
		NOEXT("do while");
 | 
						|
		spec->nextp = 0;
 | 
						|
		frchain(&spec);
 | 
						|
		return;
 | 
						|
		}
 | 
						|
	if(np->vdovar)
 | 
						|
	{
 | 
						|
		errstr("nested loops with variable %s", np->fvarname);
 | 
						|
		ctlstack->donamep = NULL;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
/* Create a memory-resident version of the index variable */
 | 
						|
 | 
						|
	dovarp = mkplace(np);
 | 
						|
	if( ! ONEOF(dovarp->vtype, MSKINT|MSKREAL) )
 | 
						|
	{
 | 
						|
		err("bad type on do variable");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	ctlstack->donamep = np;
 | 
						|
 | 
						|
	np->vdovar = YES;
 | 
						|
 | 
						|
/* Now   dovarp   points to the index to be used within the loop,   dostgp
 | 
						|
   points to the one which may need to be stored */
 | 
						|
 | 
						|
	dotype = dovarp->vtype;
 | 
						|
 | 
						|
/* Count the input specifications and type-check each one independently;
 | 
						|
   this just eliminates non-numeric values from the specification */
 | 
						|
 | 
						|
	for(i=0 , cp = spec->nextp ; cp!=NULL && i<3 ; cp = cp->nextp)
 | 
						|
	{
 | 
						|
		p = par[i++] = fixtype((tagptr)cp->datap);
 | 
						|
		if( ! ONEOF(p->headblock.vtype, MSKINT|MSKREAL) )
 | 
						|
		{
 | 
						|
			err("bad type on DO parameter");
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	frchain(&spec);
 | 
						|
	switch(i)
 | 
						|
	{
 | 
						|
	case 0:
 | 
						|
	case 1:
 | 
						|
		err("too few DO parameters");
 | 
						|
		return;
 | 
						|
 | 
						|
	default:
 | 
						|
		err("too many DO parameters");
 | 
						|
		return;
 | 
						|
 | 
						|
	case 2:
 | 
						|
		DOINCR = (expptr) ICON(1);
 | 
						|
 | 
						|
	case 3:
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
/* Now all of the local specification fields are set, but their types are
 | 
						|
   not yet consistent */
 | 
						|
 | 
						|
/* Declare the loop initialization value, casting it properly and declaring a
 | 
						|
   register if need be */
 | 
						|
 | 
						|
	if (ISCONST (DOINIT) || !onetripflag)
 | 
						|
/* putx added 6-29-89 (mwm), not sure if fixtype is required, but I doubt it
 | 
						|
   since mkconv is called just before */
 | 
						|
		doinit = putx (mkconv (dotype, DOINIT));
 | 
						|
	else {
 | 
						|
	    doinit = (expptr) mktmp(dotype, ENULL);
 | 
						|
	    puteq (cpexpr (doinit), DOINIT);
 | 
						|
	} /* else */
 | 
						|
 | 
						|
/* Declare the loop ending value, casting it to the type of the index
 | 
						|
   variable */
 | 
						|
 | 
						|
	if( ISCONST(DOLIMIT) )
 | 
						|
		ctlstack->domax = mkconv(dotype, DOLIMIT);
 | 
						|
	else {
 | 
						|
		ctlstack->domax = (expptr) mktmp0(dotype, ENULL);
 | 
						|
		puteq (cpexpr (ctlstack -> domax), DOLIMIT);
 | 
						|
	} /* else */
 | 
						|
 | 
						|
/* Declare the loop increment value, casting it to the type of the index
 | 
						|
   variable */
 | 
						|
 | 
						|
	if( ISCONST(DOINCR) )
 | 
						|
	{
 | 
						|
		ctlstack->dostep = mkconv(dotype, DOINCR);
 | 
						|
		if( (incsign = conssgn(ctlstack->dostep)) == 0)
 | 
						|
			err("zero DO increment");
 | 
						|
		ctlstack->dostepsign = (incsign > 0 ? POSSTEP : NEGSTEP);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		ctlstack->dostep = (expptr) mktmp0(dotype, ENULL);
 | 
						|
		ctlstack->dostepsign = VARSTEP;
 | 
						|
		puteq (cpexpr (ctlstack -> dostep), DOINCR);
 | 
						|
	}
 | 
						|
 | 
						|
/* All data is now properly typed and in the   ctlstack,   except for the
 | 
						|
   initial value.  Assignments of temps have been generated already */
 | 
						|
 | 
						|
	switch (ctlstack -> dostepsign) {
 | 
						|
	    case VARSTEP:
 | 
						|
		test = mkexpr (OPQUEST, mkexpr (OPLT,
 | 
						|
			cpexpr (ctlstack -> dostep), ICON(0)),
 | 
						|
			mkexpr (OPCOLON,
 | 
						|
			    mkexpr (OPGE, cpexpr((expptr)dovarp),
 | 
						|
				    cpexpr (ctlstack -> domax)),
 | 
						|
			    mkexpr (OPLE, cpexpr((expptr)dovarp),
 | 
						|
				    cpexpr (ctlstack -> domax))));
 | 
						|
		break;
 | 
						|
	    case POSSTEP:
 | 
						|
	        test = mkexpr (OPLE, cpexpr((expptr)dovarp),
 | 
						|
			cpexpr (ctlstack -> domax));
 | 
						|
	        break;
 | 
						|
	    case NEGSTEP:
 | 
						|
	        test = mkexpr (OPGE, cpexpr((expptr)dovarp),
 | 
						|
			cpexpr (ctlstack -> domax));
 | 
						|
	        break;
 | 
						|
	    default:
 | 
						|
	        erri ("exdo:  bad dostepsign '%d'", ctlstack -> dostepsign);
 | 
						|
	        break;
 | 
						|
	} /* switch (ctlstack -> dostepsign) */
 | 
						|
 | 
						|
	if (onetripflag)
 | 
						|
	    test = mkexpr (OPOR, test,
 | 
						|
		    mkexpr (OPEQ, cpexpr((expptr)dovarp), cpexpr (doinit)));
 | 
						|
	init = mkexpr (OPASSIGN, cpexpr((expptr)dovarp), doinit);
 | 
						|
	inc = mkexpr (OPPLUSEQ, (expptr)dovarp, cpexpr (ctlstack -> dostep));
 | 
						|
 | 
						|
	if (!onetripflag && ISCONST (ctlstack -> domax) && ISCONST (doinit)
 | 
						|
		&& ctlstack -> dostepsign != VARSTEP) {
 | 
						|
	    expptr tester;
 | 
						|
 | 
						|
	    tester = mkexpr (OPMINUS, cpexpr (doinit),
 | 
						|
		    cpexpr (ctlstack -> domax));
 | 
						|
	    if (incsign == conssgn (tester))
 | 
						|
		warn ("DO range never executed");
 | 
						|
	    frexpr (tester);
 | 
						|
	} /* if !onetripflag && */
 | 
						|
 | 
						|
	p1_for (init, test, inc);
 | 
						|
}
 | 
						|
 | 
						|
exenddo(np)
 | 
						|
 Namep np;
 | 
						|
{
 | 
						|
	Namep np1;
 | 
						|
	int here;
 | 
						|
	struct Ctlframe *cf;
 | 
						|
 | 
						|
	if( ctlstack < ctls )
 | 
						|
		Fatal("control stack empty");
 | 
						|
	here = ctlstack->dolabel;
 | 
						|
	if (ctlstack->ctltype != CTLDO || here >= 0) {
 | 
						|
		err("misplaced ENDDO");
 | 
						|
		return;
 | 
						|
		}
 | 
						|
	if (np != ctlstack->loopname) {
 | 
						|
		if (np1 = ctlstack->loopname)
 | 
						|
			errstr("expected \"enddo %s\"", np1->fvarname);
 | 
						|
		else
 | 
						|
			err("expected unnamed ENDDO");
 | 
						|
		for(cf = ctls; cf < ctlstack; cf++)
 | 
						|
			if (cf->ctltype == CTLDO && cf->loopname == np) {
 | 
						|
				here = cf->dolabel;
 | 
						|
				break;
 | 
						|
				}
 | 
						|
		}
 | 
						|
	enddo(here);
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
enddo(here)
 | 
						|
int here;
 | 
						|
{
 | 
						|
	register struct Ctlframe *q;
 | 
						|
	Namep np;			/* name of the current DO index */
 | 
						|
	Addrp ap;
 | 
						|
	register int i;
 | 
						|
	register expptr e;
 | 
						|
 | 
						|
/* Many DO's can end at the same statement, so keep looping over all
 | 
						|
   nested indicies */
 | 
						|
 | 
						|
	while(here == dorange)
 | 
						|
	{
 | 
						|
		if(np = ctlstack->donamep)
 | 
						|
			{
 | 
						|
			p1for_end ();
 | 
						|
 | 
						|
/* Now we're done with all of the tests, and the loop has terminated.
 | 
						|
   Store the index value back in long-term memory */
 | 
						|
 | 
						|
			if(ap = memversion(np))
 | 
						|
				puteq((expptr)ap, (expptr)mkplace(np));
 | 
						|
			for(i = 0 ; i < 4 ; ++i)
 | 
						|
				ctlstack->ctlabels[i] = 0;
 | 
						|
			deregister(ctlstack->donamep);
 | 
						|
			ctlstack->donamep->vdovar = NO;
 | 
						|
			e = ctlstack->dostep;
 | 
						|
			if (e->tag == TADDR && e->addrblock.istemp)
 | 
						|
				frtemp((Addrp)e);
 | 
						|
			else
 | 
						|
				frexpr(e);
 | 
						|
			e = ctlstack->domax;
 | 
						|
			if (e->tag == TADDR && e->addrblock.istemp)
 | 
						|
				frtemp((Addrp)e);
 | 
						|
			else
 | 
						|
				frexpr(e);
 | 
						|
			}
 | 
						|
		else if (ctlstack->dowhile)
 | 
						|
			p1for_end ();
 | 
						|
 | 
						|
/* Set   dorange   to the closing label of the next most enclosing DO loop
 | 
						|
   */
 | 
						|
 | 
						|
		popctl();
 | 
						|
		poplab();
 | 
						|
		dorange = 0;
 | 
						|
		for(q = ctlstack ; q>=ctls ; --q)
 | 
						|
			if(q->ctltype == CTLDO)
 | 
						|
			{
 | 
						|
				dorange = q->dolabel;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
exassign(vname, labelval)
 | 
						|
 register Namep vname;
 | 
						|
struct Labelblock *labelval;
 | 
						|
{
 | 
						|
	Addrp p;
 | 
						|
	expptr mkaddcon();
 | 
						|
	register Addrp q;
 | 
						|
	static char nullstr[] = "";
 | 
						|
	char *fs;
 | 
						|
	register chainp cp, cpprev;
 | 
						|
	register ftnint k, stno;
 | 
						|
 | 
						|
	p = mkplace(vname);
 | 
						|
	if( ! ONEOF(p->vtype, MSKINT|MSKADDR) ) {
 | 
						|
		err("noninteger assign variable");
 | 
						|
		return;
 | 
						|
		}
 | 
						|
 | 
						|
	/* If the label hasn't been defined, then we do things twice:
 | 
						|
	 * once for an executable stmt label, once for a format
 | 
						|
	 */
 | 
						|
 | 
						|
	/* code for executable label... */
 | 
						|
 | 
						|
/* Now store the assigned value in a list associated with this variable.
 | 
						|
   This will be used later to generate a switch() statement in the C output */
 | 
						|
 | 
						|
	if (!labelval->labdefined || !labelval->fmtstring) {
 | 
						|
 | 
						|
		if (vname -> vis_assigned == 0) {
 | 
						|
			vname -> varxptr.assigned_values = CHNULL;
 | 
						|
			vname -> vis_assigned = 1;
 | 
						|
			}
 | 
						|
 | 
						|
		/* don't duplicate labels... */
 | 
						|
 | 
						|
		stno = labelval->stateno;
 | 
						|
		cpprev = 0;
 | 
						|
		for(k = 0, cp = vname->varxptr.assigned_values;
 | 
						|
				cp; cpprev = cp, cp = cp->nextp, k++)
 | 
						|
			if ((ftnint)cp->datap == stno)
 | 
						|
				break;
 | 
						|
		if (!cp) {
 | 
						|
			cp = mkchain((char *)stno, CHNULL);
 | 
						|
			if (cpprev)
 | 
						|
				cpprev->nextp = cp;
 | 
						|
			else
 | 
						|
				vname->varxptr.assigned_values = cp;
 | 
						|
			labelval->labused = 1;
 | 
						|
			}
 | 
						|
		putout(mkexpr(OPASSIGN, (expptr)p, mkintcon(k)));
 | 
						|
		}
 | 
						|
 | 
						|
	/* Code for FORMAT label... */
 | 
						|
 | 
						|
	fs = labelval->fmtstring;
 | 
						|
	if (!labelval->labdefined || fs && fs != nullstr) {
 | 
						|
		extern void fmtname();
 | 
						|
 | 
						|
		if (!fs)
 | 
						|
			labelval->fmtstring = nullstr;
 | 
						|
		labelval->fmtlabused = 1;
 | 
						|
		p = ALLOC(Addrblock);
 | 
						|
		p->tag = TADDR;
 | 
						|
		p->vtype = TYCHAR;
 | 
						|
		p->vstg = STGAUTO;
 | 
						|
		p->memoffset = ICON(0);
 | 
						|
		fmtname(vname, p);
 | 
						|
		q = ALLOC(Addrblock);
 | 
						|
		q->tag = TADDR;
 | 
						|
		q->vtype = TYCHAR;
 | 
						|
		q->vstg = STGAUTO;
 | 
						|
		q->ntempelt = 1;
 | 
						|
		q->memoffset = ICON(0);
 | 
						|
		q->uname_tag = UNAM_IDENT;
 | 
						|
		sprintf(q->user.ident, "fmt_%ld", labelval->stateno);
 | 
						|
		putout(mkexpr(OPASSIGN, (expptr)p, (expptr)q));
 | 
						|
		}
 | 
						|
 | 
						|
} /* exassign */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
exarif(expr, neglab, zerlab, poslab)
 | 
						|
expptr expr;
 | 
						|
struct Labelblock *neglab, *zerlab, *poslab;
 | 
						|
{
 | 
						|
    register int lm, lz, lp;
 | 
						|
 | 
						|
    lm = neglab->stateno;
 | 
						|
    lz = zerlab->stateno;
 | 
						|
    lp = poslab->stateno;
 | 
						|
    expr = fixtype(expr);
 | 
						|
 | 
						|
    if( ! ONEOF(expr->headblock.vtype, MSKINT|MSKREAL) )
 | 
						|
    {
 | 
						|
        err("invalid type of arithmetic if expression");
 | 
						|
        frexpr(expr);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        if (lm == lz && lz == lp)
 | 
						|
            exgoto (neglab);
 | 
						|
        else if(lm == lz)
 | 
						|
            exar2(OPLE, expr, neglab, poslab);
 | 
						|
        else if(lm == lp)
 | 
						|
            exar2(OPNE, expr, neglab, zerlab);
 | 
						|
        else if(lz == lp)
 | 
						|
            exar2(OPGE, expr, zerlab, neglab);
 | 
						|
        else {
 | 
						|
            expptr t;
 | 
						|
 | 
						|
	    if (!addressable (expr)) {
 | 
						|
		t = (expptr) mktmp(expr -> headblock.vtype, ENULL);
 | 
						|
		expr = mkexpr (OPASSIGN, cpexpr (t), expr);
 | 
						|
	    } else
 | 
						|
		t = (expptr) cpexpr (expr);
 | 
						|
 | 
						|
	    p1_if(putx(fixtype(mkexpr (OPLT, expr, ICON (0)))));
 | 
						|
	    exgoto(neglab);
 | 
						|
	    p1_elif (mkexpr (OPEQ, t, ICON (0)));
 | 
						|
	    exgoto(zerlab);
 | 
						|
	    p1_else ();
 | 
						|
	    exgoto(poslab);
 | 
						|
	    p1else_end ();
 | 
						|
        } /* else */
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* exar2 -- Do arithmetic IF for only 2 distinct labels;   if !(e.op.0)
 | 
						|
   goto l2 else goto l1.  If this seems backwards, that's because it is,
 | 
						|
   in order to make the 1 pass algorithm work. */
 | 
						|
 | 
						|
 LOCAL void
 | 
						|
exar2(op, e, l1, l2)
 | 
						|
 int op;
 | 
						|
 expptr e;
 | 
						|
 struct Labelblock *l1, *l2;
 | 
						|
{
 | 
						|
	expptr comp;
 | 
						|
 | 
						|
	comp = mkexpr (op, e, ICON (0));
 | 
						|
	p1_if(putx(fixtype(comp)));
 | 
						|
	exgoto(l1);
 | 
						|
	p1_else ();
 | 
						|
	exgoto(l2);
 | 
						|
	p1else_end ();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* exreturn -- return the value in   p  from a SUBROUTINE call -- used to
 | 
						|
   implement the alternate return mechanism */
 | 
						|
 | 
						|
exreturn(p)
 | 
						|
register expptr p;
 | 
						|
{
 | 
						|
	if(procclass != CLPROC)
 | 
						|
		warn("RETURN statement in main or block data");
 | 
						|
	if(p && (proctype!=TYSUBR || procclass!=CLPROC) )
 | 
						|
	{
 | 
						|
		err("alternate return in nonsubroutine");
 | 
						|
		p = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (p || proctype == TYSUBR) {
 | 
						|
		if (p == ENULL) p = ICON (0);
 | 
						|
		p = mkconv (TYLONG, fixtype (p));
 | 
						|
		p1_subr_ret (p);
 | 
						|
	} /* if p || proctype == TYSUBR */
 | 
						|
	else
 | 
						|
	    p1_subr_ret((expptr)retslot);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
exasgoto(labvar)
 | 
						|
Namep labvar;
 | 
						|
{
 | 
						|
	register Addrp p;
 | 
						|
	void p1_asgoto();
 | 
						|
 | 
						|
	p = mkplace(labvar);
 | 
						|
	if( ! ISINT(p->vtype) )
 | 
						|
		err("assigned goto variable must be integer");
 | 
						|
	else {
 | 
						|
		p1_asgoto (p);
 | 
						|
	} /* else */
 | 
						|
}
 |