832 lines
18 KiB
C
832 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 */
|
||
|
}
|