1042 lines
17 KiB
C
1042 lines
17 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"
|
||
|
|
||
|
int oneof_stg (name, stg, mask)
|
||
|
Namep name;
|
||
|
int stg, mask;
|
||
|
{
|
||
|
if (stg == STGCOMMON && name) {
|
||
|
if ((mask & M(STGEQUIV)))
|
||
|
return name->vcommequiv;
|
||
|
if ((mask & M(STGCOMMON)))
|
||
|
return !name->vcommequiv;
|
||
|
}
|
||
|
return ONEOF(stg, mask);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* op_assign -- given a binary opcode, return the associated assignment
|
||
|
operator */
|
||
|
|
||
|
int op_assign (opcode)
|
||
|
int opcode;
|
||
|
{
|
||
|
int retval = -1;
|
||
|
|
||
|
switch (opcode) {
|
||
|
case OPPLUS: retval = OPPLUSEQ; break;
|
||
|
case OPMINUS: retval = OPMINUSEQ; break;
|
||
|
case OPSTAR: retval = OPSTAREQ; break;
|
||
|
case OPSLASH: retval = OPSLASHEQ; break;
|
||
|
case OPMOD: retval = OPMODEQ; break;
|
||
|
case OPLSHIFT: retval = OPLSHIFTEQ; break;
|
||
|
case OPRSHIFT: retval = OPRSHIFTEQ; break;
|
||
|
case OPBITAND: retval = OPBITANDEQ; break;
|
||
|
case OPBITXOR: retval = OPBITXOREQ; break;
|
||
|
case OPBITOR: retval = OPBITOREQ; break;
|
||
|
default:
|
||
|
erri ("op_assign: bad opcode '%d'", opcode);
|
||
|
break;
|
||
|
} /* switch */
|
||
|
|
||
|
return retval;
|
||
|
} /* op_assign */
|
||
|
|
||
|
|
||
|
char *
|
||
|
Alloc(n) /* error-checking version of malloc */
|
||
|
/* ckalloc initializes memory to 0; Alloc does not */
|
||
|
int n;
|
||
|
{
|
||
|
char errbuf[32];
|
||
|
register char *rv;
|
||
|
|
||
|
rv = malloc(n);
|
||
|
if (!rv) {
|
||
|
sprintf(errbuf, "malloc(%d) failure!", n);
|
||
|
Fatal(errbuf);
|
||
|
}
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
|
||
|
cpn(n, a, b)
|
||
|
register int n;
|
||
|
register char *a, *b;
|
||
|
{
|
||
|
while(--n >= 0)
|
||
|
*b++ = *a++;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
eqn(n, a, b)
|
||
|
register int n;
|
||
|
register char *a, *b;
|
||
|
{
|
||
|
while(--n >= 0)
|
||
|
if(*a++ != *b++)
|
||
|
return(NO);
|
||
|
return(YES);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
cmpstr(a, b, la, lb) /* compare two strings */
|
||
|
register char *a, *b;
|
||
|
ftnint la, lb;
|
||
|
{
|
||
|
register char *aend, *bend;
|
||
|
aend = a + la;
|
||
|
bend = b + lb;
|
||
|
|
||
|
|
||
|
if(la <= lb)
|
||
|
{
|
||
|
while(a < aend)
|
||
|
if(*a != *b)
|
||
|
return( *a - *b );
|
||
|
else
|
||
|
{
|
||
|
++a;
|
||
|
++b;
|
||
|
}
|
||
|
|
||
|
while(b < bend)
|
||
|
if(*b != ' ')
|
||
|
return(' ' - *b);
|
||
|
else
|
||
|
++b;
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
while(b < bend)
|
||
|
if(*a != *b)
|
||
|
return( *a - *b );
|
||
|
else
|
||
|
{
|
||
|
++a;
|
||
|
++b;
|
||
|
}
|
||
|
while(a < aend)
|
||
|
if(*a != ' ')
|
||
|
return(*a - ' ');
|
||
|
else
|
||
|
++a;
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* hookup -- Same as LISP NCONC, that is a destructive append of two lists */
|
||
|
|
||
|
chainp hookup(x,y)
|
||
|
register chainp x, y;
|
||
|
{
|
||
|
register chainp p;
|
||
|
|
||
|
if(x == NULL)
|
||
|
return(y);
|
||
|
|
||
|
for(p = x ; p->nextp ; p = p->nextp)
|
||
|
;
|
||
|
p->nextp = y;
|
||
|
return(x);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
struct Listblock *mklist(p)
|
||
|
chainp p;
|
||
|
{
|
||
|
register struct Listblock *q;
|
||
|
|
||
|
q = ALLOC(Listblock);
|
||
|
q->tag = TLIST;
|
||
|
q->listp = p;
|
||
|
return(q);
|
||
|
}
|
||
|
|
||
|
|
||
|
chainp mkchain(p,q)
|
||
|
register char * p;
|
||
|
register chainp q;
|
||
|
{
|
||
|
register chainp r;
|
||
|
|
||
|
if(chains)
|
||
|
{
|
||
|
r = chains;
|
||
|
chains = chains->nextp;
|
||
|
}
|
||
|
else
|
||
|
r = ALLOC(Chain);
|
||
|
|
||
|
r->datap = p;
|
||
|
r->nextp = q;
|
||
|
return(r);
|
||
|
}
|
||
|
|
||
|
chainp
|
||
|
revchain(next)
|
||
|
register chainp next;
|
||
|
{
|
||
|
register chainp p, prev = 0;
|
||
|
|
||
|
while(p = next) {
|
||
|
next = p->nextp;
|
||
|
p->nextp = prev;
|
||
|
prev = p;
|
||
|
}
|
||
|
return prev;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* addunder -- turn a cvarname into an external name */
|
||
|
/* The cvarname may already end in _ (to avoid C keywords); */
|
||
|
/* if not, it has room for appending an _. */
|
||
|
|
||
|
char *
|
||
|
addunder(s)
|
||
|
register char *s;
|
||
|
{
|
||
|
register int c, i;
|
||
|
char *s0 = s;
|
||
|
|
||
|
i = 0;
|
||
|
while(c = *s++)
|
||
|
if (c == '_')
|
||
|
i++;
|
||
|
else
|
||
|
i = 0;
|
||
|
if (!i) {
|
||
|
*s-- = 0;
|
||
|
*s = '_';
|
||
|
}
|
||
|
return( s0 );
|
||
|
}
|
||
|
|
||
|
|
||
|
/* copyn -- return a new copy of the input Fortran-string */
|
||
|
|
||
|
char *copyn(n, s)
|
||
|
register int n;
|
||
|
register char *s;
|
||
|
{
|
||
|
register char *p, *q;
|
||
|
|
||
|
p = q = (char *) Alloc(n);
|
||
|
while(--n >= 0)
|
||
|
*q++ = *s++;
|
||
|
return(p);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* copys -- return a new copy of the input C-string */
|
||
|
|
||
|
char *copys(s)
|
||
|
char *s;
|
||
|
{
|
||
|
return( copyn( strlen(s)+1 , s) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* convci -- Convert Fortran-string to integer; assumes that input is a
|
||
|
legal number, with no trailing blanks */
|
||
|
|
||
|
ftnint convci(n, s)
|
||
|
register int n;
|
||
|
register char *s;
|
||
|
{
|
||
|
ftnint sum;
|
||
|
sum = 0;
|
||
|
while(n-- > 0)
|
||
|
sum = 10*sum + (*s++ - '0');
|
||
|
return(sum);
|
||
|
}
|
||
|
|
||
|
/* convic - Convert Integer constant to string */
|
||
|
|
||
|
char *convic(n)
|
||
|
ftnint n;
|
||
|
{
|
||
|
static char s[20];
|
||
|
register char *t;
|
||
|
|
||
|
s[19] = '\0';
|
||
|
t = s+19;
|
||
|
|
||
|
do {
|
||
|
*--t = '0' + n%10;
|
||
|
n /= 10;
|
||
|
} while(n > 0);
|
||
|
|
||
|
return(t);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* mkname -- add a new identifier to the environment, including the closed
|
||
|
hash table. */
|
||
|
|
||
|
Namep mkname(s)
|
||
|
register char *s;
|
||
|
{
|
||
|
struct Hashentry *hp;
|
||
|
register Namep q;
|
||
|
register int c, hash, i;
|
||
|
register char *t;
|
||
|
char *s0;
|
||
|
char errbuf[64];
|
||
|
|
||
|
hash = i = 0;
|
||
|
s0 = s;
|
||
|
while(c = *s++) {
|
||
|
hash += c;
|
||
|
if (c == '_')
|
||
|
i = 1;
|
||
|
}
|
||
|
hash %= maxhash;
|
||
|
|
||
|
/* Add the name to the closed hash table */
|
||
|
|
||
|
hp = hashtab + hash;
|
||
|
|
||
|
while(q = hp->varp)
|
||
|
if( hash == hp->hashval && !strcmp(s0,q->fvarname) )
|
||
|
return(q);
|
||
|
else if(++hp >= lasthash)
|
||
|
hp = hashtab;
|
||
|
|
||
|
if(++nintnames >= maxhash-1)
|
||
|
many("names", 'n', maxhash); /* Fatal error */
|
||
|
hp->varp = q = ALLOC(Nameblock);
|
||
|
hp->hashval = hash;
|
||
|
q->tag = TNAME; /* TNAME means the tag type is NAME */
|
||
|
c = s - s0;
|
||
|
if (c > 7 && noextflag) {
|
||
|
sprintf(errbuf, "\"%.35s%s\" over 6 characters long", s0,
|
||
|
c > 36 ? "..." : "");
|
||
|
errext(errbuf);
|
||
|
}
|
||
|
q->fvarname = strcpy(mem(c,0), s0);
|
||
|
t = q->cvarname = mem(c + i + 1, 0);
|
||
|
s = s0;
|
||
|
/* add __ to the end of any name containing _ */
|
||
|
while(*t = *s++)
|
||
|
t++;
|
||
|
if (i) {
|
||
|
t[0] = t[1] = '_';
|
||
|
t[2] = 0;
|
||
|
}
|
||
|
else if (in_vector(s0) >= 0) {
|
||
|
t[0] = '_';
|
||
|
t[1] = 0;
|
||
|
}
|
||
|
return(q);
|
||
|
}
|
||
|
|
||
|
|
||
|
struct Labelblock *mklabel(l)
|
||
|
ftnint l;
|
||
|
{
|
||
|
register struct Labelblock *lp;
|
||
|
|
||
|
if(l <= 0)
|
||
|
return(NULL);
|
||
|
|
||
|
for(lp = labeltab ; lp < highlabtab ; ++lp)
|
||
|
if(lp->stateno == l)
|
||
|
return(lp);
|
||
|
|
||
|
if(++highlabtab > labtabend)
|
||
|
many("statement labels", 's', maxstno);
|
||
|
|
||
|
lp->stateno = l;
|
||
|
lp->labelno = newlabel();
|
||
|
lp->blklevel = 0;
|
||
|
lp->labused = NO;
|
||
|
lp->fmtlabused = NO;
|
||
|
lp->labdefined = NO;
|
||
|
lp->labinacc = NO;
|
||
|
lp->labtype = LABUNKNOWN;
|
||
|
lp->fmtstring = 0;
|
||
|
return(lp);
|
||
|
}
|
||
|
|
||
|
|
||
|
newlabel()
|
||
|
{
|
||
|
return( ++lastlabno );
|
||
|
}
|
||
|
|
||
|
|
||
|
/* this label appears in a branch context */
|
||
|
|
||
|
struct Labelblock *execlab(stateno)
|
||
|
ftnint stateno;
|
||
|
{
|
||
|
register struct Labelblock *lp;
|
||
|
|
||
|
if(lp = mklabel(stateno))
|
||
|
{
|
||
|
if(lp->labinacc)
|
||
|
warn1("illegal branch to inner block, statement label %s",
|
||
|
convic(stateno) );
|
||
|
else if(lp->labdefined == NO)
|
||
|
lp->blklevel = blklevel;
|
||
|
if(lp->labtype == LABFORMAT)
|
||
|
err("may not branch to a format");
|
||
|
else
|
||
|
lp->labtype = LABEXEC;
|
||
|
}
|
||
|
else
|
||
|
execerr("illegal label %s", convic(stateno));
|
||
|
|
||
|
return(lp);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* find or put a name in the external symbol table */
|
||
|
|
||
|
Extsym *mkext(f,s)
|
||
|
char *f, *s;
|
||
|
{
|
||
|
Extsym *p;
|
||
|
|
||
|
for(p = extsymtab ; p<nextext ; ++p)
|
||
|
if(!strcmp(s,p->cextname))
|
||
|
return( p );
|
||
|
|
||
|
if(nextext >= lastext)
|
||
|
many("external symbols", 'x', maxext);
|
||
|
|
||
|
nextext->fextname = strcpy(gmem(strlen(f)+1,0), f);
|
||
|
nextext->cextname = f == s
|
||
|
? nextext->fextname
|
||
|
: strcpy(gmem(strlen(s)+1,0), s);
|
||
|
nextext->extstg = STGUNKNOWN;
|
||
|
nextext->extp = 0;
|
||
|
nextext->allextp = 0;
|
||
|
nextext->extleng = 0;
|
||
|
nextext->maxleng = 0;
|
||
|
nextext->extinit = 0;
|
||
|
nextext->curno = nextext->maxno = 0;
|
||
|
return( nextext++ );
|
||
|
}
|
||
|
|
||
|
|
||
|
Addrp builtin(t, s, dbi)
|
||
|
int t, dbi;
|
||
|
char *s;
|
||
|
{
|
||
|
register Extsym *p;
|
||
|
register Addrp q;
|
||
|
extern chainp used_builtins;
|
||
|
|
||
|
p = mkext(s,s);
|
||
|
if(p->extstg == STGUNKNOWN)
|
||
|
p->extstg = STGEXT;
|
||
|
else if(p->extstg != STGEXT)
|
||
|
{
|
||
|
errstr("improper use of builtin %s", s);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
q = ALLOC(Addrblock);
|
||
|
q->tag = TADDR;
|
||
|
q->vtype = t;
|
||
|
q->vclass = CLPROC;
|
||
|
q->vstg = STGEXT;
|
||
|
q->memno = p - extsymtab;
|
||
|
q->dbl_builtin = dbi;
|
||
|
|
||
|
/* A NULL pointer here tells you to use memno to check the external
|
||
|
symbol table */
|
||
|
|
||
|
q -> uname_tag = UNAM_EXTERN;
|
||
|
|
||
|
/* Add to the list of used builtins */
|
||
|
|
||
|
if (dbi >= 0)
|
||
|
add_extern_to_list (q, &used_builtins);
|
||
|
return(q);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
add_extern_to_list (addr, list_store)
|
||
|
Addrp addr;
|
||
|
chainp *list_store;
|
||
|
{
|
||
|
chainp last = CHNULL;
|
||
|
chainp list;
|
||
|
int memno;
|
||
|
|
||
|
if (list_store == (chainp *) NULL || addr == (Addrp) NULL)
|
||
|
return;
|
||
|
|
||
|
list = *list_store;
|
||
|
memno = addr -> memno;
|
||
|
|
||
|
for (;list; last = list, list = list -> nextp) {
|
||
|
Addrp this = (Addrp) (list -> datap);
|
||
|
|
||
|
if (this -> tag == TADDR && this -> uname_tag == UNAM_EXTERN &&
|
||
|
this -> memno == memno)
|
||
|
return;
|
||
|
} /* for */
|
||
|
|
||
|
if (*list_store == CHNULL)
|
||
|
*list_store = mkchain((char *)cpexpr((expptr)addr), CHNULL);
|
||
|
else
|
||
|
last->nextp = mkchain((char *)cpexpr((expptr)addr), CHNULL);
|
||
|
|
||
|
} /* add_extern_to_list */
|
||
|
|
||
|
|
||
|
frchain(p)
|
||
|
register chainp *p;
|
||
|
{
|
||
|
register chainp q;
|
||
|
|
||
|
if(p==0 || *p==0)
|
||
|
return;
|
||
|
|
||
|
for(q = *p; q->nextp ; q = q->nextp)
|
||
|
;
|
||
|
q->nextp = chains;
|
||
|
chains = *p;
|
||
|
*p = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
frexchain(p)
|
||
|
register chainp *p;
|
||
|
{
|
||
|
register chainp q, r;
|
||
|
|
||
|
if (q = *p) {
|
||
|
for(;;q = r) {
|
||
|
frexpr((expptr)q->datap);
|
||
|
if (!(r = q->nextp))
|
||
|
break;
|
||
|
}
|
||
|
q->nextp = chains;
|
||
|
chains = *p;
|
||
|
*p = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
tagptr cpblock(n,p)
|
||
|
register int n;
|
||
|
register char * p;
|
||
|
{
|
||
|
register ptr q;
|
||
|
|
||
|
memcpy((char *)(q = ckalloc(n)), (char *)p, n);
|
||
|
return( (tagptr) q);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
ftnint lmax(a, b)
|
||
|
ftnint a, b;
|
||
|
{
|
||
|
return( a>b ? a : b);
|
||
|
}
|
||
|
|
||
|
ftnint lmin(a, b)
|
||
|
ftnint a, b;
|
||
|
{
|
||
|
return(a < b ? a : b);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
maxtype(t1, t2)
|
||
|
int t1, t2;
|
||
|
{
|
||
|
int t;
|
||
|
|
||
|
t = t1 >= t2 ? t1 : t2;
|
||
|
if(t==TYCOMPLEX && (t1==TYDREAL || t2==TYDREAL) )
|
||
|
t = TYDCOMPLEX;
|
||
|
return(t);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* return log base 2 of n if n a power of 2; otherwise -1 */
|
||
|
log_2(n)
|
||
|
ftnint n;
|
||
|
{
|
||
|
int k;
|
||
|
|
||
|
/* trick based on binary representation */
|
||
|
|
||
|
if(n<=0 || (n & (n-1))!=0)
|
||
|
return(-1);
|
||
|
|
||
|
for(k = 0 ; n >>= 1 ; ++k)
|
||
|
;
|
||
|
return(k);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
frrpl()
|
||
|
{
|
||
|
struct Rplblock *rp;
|
||
|
|
||
|
while(rpllist)
|
||
|
{
|
||
|
rp = rpllist->rplnextp;
|
||
|
free( (charptr) rpllist);
|
||
|
rpllist = rp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Call a Fortran function with an arbitrary list of arguments */
|
||
|
|
||
|
int callk_kludge;
|
||
|
|
||
|
expptr callk(type, name, args)
|
||
|
int type;
|
||
|
char *name;
|
||
|
chainp args;
|
||
|
{
|
||
|
register expptr p;
|
||
|
|
||
|
p = mkexpr(OPCALL,
|
||
|
(expptr)builtin(callk_kludge ? callk_kludge : type, name, 0),
|
||
|
(expptr)args);
|
||
|
p->exprblock.vtype = type;
|
||
|
return(p);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
expptr call4(type, name, arg1, arg2, arg3, arg4)
|
||
|
int type;
|
||
|
char *name;
|
||
|
expptr arg1, arg2, arg3, arg4;
|
||
|
{
|
||
|
struct Listblock *args;
|
||
|
args = mklist( mkchain((char *)arg1,
|
||
|
mkchain((char *)arg2,
|
||
|
mkchain((char *)arg3,
|
||
|
mkchain((char *)arg4, CHNULL)) ) ) );
|
||
|
return( callk(type, name, (chainp)args) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
expptr call3(type, name, arg1, arg2, arg3)
|
||
|
int type;
|
||
|
char *name;
|
||
|
expptr arg1, arg2, arg3;
|
||
|
{
|
||
|
struct Listblock *args;
|
||
|
args = mklist( mkchain((char *)arg1,
|
||
|
mkchain((char *)arg2,
|
||
|
mkchain((char *)arg3, CHNULL) ) ) );
|
||
|
return( callk(type, name, (chainp)args) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
expptr call2(type, name, arg1, arg2)
|
||
|
int type;
|
||
|
char *name;
|
||
|
expptr arg1, arg2;
|
||
|
{
|
||
|
struct Listblock *args;
|
||
|
|
||
|
args = mklist( mkchain((char *)arg1, mkchain((char *)arg2, CHNULL) ) );
|
||
|
return( callk(type,name, (chainp)args) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
expptr call1(type, name, arg)
|
||
|
int type;
|
||
|
char *name;
|
||
|
expptr arg;
|
||
|
{
|
||
|
return( callk(type,name, (chainp)mklist(mkchain((char *)arg,CHNULL)) ));
|
||
|
}
|
||
|
|
||
|
|
||
|
expptr call0(type, name)
|
||
|
int type;
|
||
|
char *name;
|
||
|
{
|
||
|
return( callk(type, name, CHNULL) );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
struct Impldoblock *mkiodo(dospec, list)
|
||
|
chainp dospec, list;
|
||
|
{
|
||
|
register struct Impldoblock *q;
|
||
|
|
||
|
q = ALLOC(Impldoblock);
|
||
|
q->tag = TIMPLDO;
|
||
|
q->impdospec = dospec;
|
||
|
q->datalist = list;
|
||
|
return(q);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* ckalloc -- Allocate 1 memory unit of size n, checking for out of
|
||
|
memory error */
|
||
|
|
||
|
ptr ckalloc(n)
|
||
|
register int n;
|
||
|
{
|
||
|
register ptr p;
|
||
|
if( p = (ptr)calloc(1, (unsigned) n) )
|
||
|
return(p);
|
||
|
fprintf(stderr, "failing to get %d bytes\n",n);
|
||
|
Fatal("out of memory");
|
||
|
/* NOT REACHED */ return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
isaddr(p)
|
||
|
register expptr p;
|
||
|
{
|
||
|
if(p->tag == TADDR)
|
||
|
return(YES);
|
||
|
if(p->tag == TEXPR)
|
||
|
switch(p->exprblock.opcode)
|
||
|
{
|
||
|
case OPCOMMA:
|
||
|
return( isaddr(p->exprblock.rightp) );
|
||
|
|
||
|
case OPASSIGN:
|
||
|
case OPASSIGNI:
|
||
|
case OPPLUSEQ:
|
||
|
case OPMINUSEQ:
|
||
|
case OPSLASHEQ:
|
||
|
case OPMODEQ:
|
||
|
case OPLSHIFTEQ:
|
||
|
case OPRSHIFTEQ:
|
||
|
case OPBITANDEQ:
|
||
|
case OPBITXOREQ:
|
||
|
case OPBITOREQ:
|
||
|
return( isaddr(p->exprblock.leftp) );
|
||
|
}
|
||
|
return(NO);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
isstatic(p)
|
||
|
register expptr p;
|
||
|
{
|
||
|
extern int useauto;
|
||
|
if(p->headblock.vleng && !ISCONST(p->headblock.vleng))
|
||
|
return(NO);
|
||
|
|
||
|
switch(p->tag)
|
||
|
{
|
||
|
case TCONST:
|
||
|
return(YES);
|
||
|
|
||
|
case TADDR:
|
||
|
if(ONEOF(p->addrblock.vstg,MSKSTATIC) &&
|
||
|
ISCONST(p->addrblock.memoffset) && !useauto)
|
||
|
return(YES);
|
||
|
|
||
|
default:
|
||
|
return(NO);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* addressable -- return True iff it is a constant value, or can be
|
||
|
referenced by constant values */
|
||
|
|
||
|
addressable(p)
|
||
|
register expptr p;
|
||
|
{
|
||
|
switch(p->tag)
|
||
|
{
|
||
|
case TCONST:
|
||
|
return(YES);
|
||
|
|
||
|
case TADDR:
|
||
|
return( addressable(p->addrblock.memoffset) );
|
||
|
|
||
|
default:
|
||
|
return(NO);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* isnegative_const -- returns true if the constant is negative. Returns
|
||
|
false for imaginary and nonnumeric constants */
|
||
|
|
||
|
int isnegative_const (cp)
|
||
|
struct Constblock *cp;
|
||
|
{
|
||
|
int retval;
|
||
|
|
||
|
if (cp == NULL)
|
||
|
return 0;
|
||
|
|
||
|
switch (cp -> vtype) {
|
||
|
case TYSHORT:
|
||
|
case TYLONG:
|
||
|
retval = cp -> Const.ci < 0;
|
||
|
break;
|
||
|
case TYREAL:
|
||
|
case TYDREAL:
|
||
|
retval = cp->vstg ? *cp->Const.cds[0] == '-'
|
||
|
: cp->Const.cd[0] < 0.0;
|
||
|
break;
|
||
|
default:
|
||
|
|
||
|
retval = 0;
|
||
|
break;
|
||
|
} /* switch */
|
||
|
|
||
|
return retval;
|
||
|
} /* isnegative_const */
|
||
|
|
||
|
negate_const(cp)
|
||
|
Constp cp;
|
||
|
{
|
||
|
if (cp == (struct Constblock *) NULL)
|
||
|
return;
|
||
|
|
||
|
switch (cp -> vtype) {
|
||
|
case TYSHORT:
|
||
|
case TYLONG:
|
||
|
cp -> Const.ci = - cp -> Const.ci;
|
||
|
break;
|
||
|
case TYCOMPLEX:
|
||
|
case TYDCOMPLEX:
|
||
|
if (cp->vstg)
|
||
|
switch(*cp->Const.cds[1]) {
|
||
|
case '-':
|
||
|
++cp->Const.cds[1];
|
||
|
break;
|
||
|
case '0':
|
||
|
break;
|
||
|
default:
|
||
|
--cp->Const.cds[1];
|
||
|
}
|
||
|
else
|
||
|
cp->Const.cd[1] = -cp->Const.cd[1];
|
||
|
/* no break */
|
||
|
case TYREAL:
|
||
|
case TYDREAL:
|
||
|
if (cp->vstg)
|
||
|
switch(*cp->Const.cds[0]) {
|
||
|
case '-':
|
||
|
++cp->Const.cds[0];
|
||
|
break;
|
||
|
case '0':
|
||
|
break;
|
||
|
default:
|
||
|
--cp->Const.cds[0];
|
||
|
}
|
||
|
else
|
||
|
cp->Const.cd[0] = -cp->Const.cd[0];
|
||
|
break;
|
||
|
case TYCHAR:
|
||
|
case TYLOGICAL:
|
||
|
erri ("negate_const: can't negate type '%d'", cp -> vtype);
|
||
|
break;
|
||
|
default:
|
||
|
erri ("negate_const: bad type '%d'",
|
||
|
cp -> vtype);
|
||
|
break;
|
||
|
} /* switch */
|
||
|
} /* negate_const */
|
||
|
|
||
|
ffilecopy (infp, outfp)
|
||
|
FILE *infp, *outfp;
|
||
|
{
|
||
|
while (!feof (infp)) {
|
||
|
register c = getc (infp);
|
||
|
if (!feof (infp))
|
||
|
putc (c, outfp);
|
||
|
} /* while */
|
||
|
} /* ffilecopy */
|
||
|
|
||
|
|
||
|
#define NOT_IN_VECTOR -1
|
||
|
|
||
|
/* in_vector -- verifies whether str is in c_keywords.
|
||
|
If so, the index is returned else NOT_IN_VECTOR is returned.
|
||
|
c_keywords must be in alphabetical order (as defined by strcmp).
|
||
|
*/
|
||
|
|
||
|
int in_vector(str)
|
||
|
char *str;
|
||
|
{
|
||
|
extern int n_keywords;
|
||
|
extern char *c_keywords[];
|
||
|
register int n = n_keywords;
|
||
|
register char **K = c_keywords;
|
||
|
register int n1, t;
|
||
|
|
||
|
do {
|
||
|
n1 = n >> 1;
|
||
|
if (!(t = strcmp(str, K[n1])))
|
||
|
return K - c_keywords + n1;
|
||
|
if (t < 0)
|
||
|
n = n1;
|
||
|
else {
|
||
|
n -= ++n1;
|
||
|
K += n1;
|
||
|
}
|
||
|
}
|
||
|
while(n > 0);
|
||
|
|
||
|
return NOT_IN_VECTOR;
|
||
|
} /* in_vector */
|
||
|
|
||
|
|
||
|
int is_negatable (Const)
|
||
|
Constp Const;
|
||
|
{
|
||
|
int retval = 0;
|
||
|
if (Const != (Constp) NULL)
|
||
|
switch (Const -> vtype) {
|
||
|
case TYSHORT:
|
||
|
retval = Const -> Const.ci >= -BIGGEST_SHORT;
|
||
|
break;
|
||
|
case TYLONG:
|
||
|
retval = Const -> Const.ci >= -BIGGEST_LONG;
|
||
|
break;
|
||
|
case TYREAL:
|
||
|
case TYDREAL:
|
||
|
case TYCOMPLEX:
|
||
|
case TYDCOMPLEX:
|
||
|
retval = 1;
|
||
|
break;
|
||
|
case TYLOGICAL:
|
||
|
case TYCHAR:
|
||
|
case TYSUBR:
|
||
|
default:
|
||
|
retval = 0;
|
||
|
break;
|
||
|
} /* switch */
|
||
|
|
||
|
return retval;
|
||
|
} /* is_negatable */
|
||
|
|
||
|
backup(fname, bname)
|
||
|
char *fname, *bname;
|
||
|
{
|
||
|
FILE *b, *f;
|
||
|
static char couldnt[] = "Couldn't open %.80s";
|
||
|
|
||
|
if (!(f = fopen(fname, binread))) {
|
||
|
warn1(couldnt, fname);
|
||
|
return;
|
||
|
}
|
||
|
if (!(b = fopen(bname, binwrite))) {
|
||
|
warn1(couldnt, bname);
|
||
|
return;
|
||
|
}
|
||
|
ffilecopy(f, b);
|
||
|
fclose(f);
|
||
|
fclose(b);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* struct_eq -- returns YES if structures have the same field names and
|
||
|
types, NO otherwise */
|
||
|
|
||
|
int struct_eq (s1, s2)
|
||
|
chainp s1, s2;
|
||
|
{
|
||
|
struct Dimblock *d1, *d2;
|
||
|
Constp cp1, cp2;
|
||
|
|
||
|
if (s1 == CHNULL && s2 == CHNULL)
|
||
|
return YES;
|
||
|
for(; s1 && s2; s1 = s1->nextp, s2 = s2->nextp) {
|
||
|
register Namep v1 = (Namep) s1 -> datap;
|
||
|
register Namep v2 = (Namep) s2 -> datap;
|
||
|
|
||
|
if (v1 == (Namep) NULL || v1 -> tag != TNAME ||
|
||
|
v2 == (Namep) NULL || v2 -> tag != TNAME)
|
||
|
return NO;
|
||
|
|
||
|
if (v1->vtype != v2->vtype || v1->vclass != v2->vclass
|
||
|
|| strcmp(v1->fvarname, v2->fvarname))
|
||
|
return NO;
|
||
|
|
||
|
/* compare dimensions (needed for comparing COMMON blocks) */
|
||
|
|
||
|
if (d1 = v1->vdim) {
|
||
|
if (!(cp1 = (Constp)d1->nelt) || cp1->tag != TCONST)
|
||
|
return NO;
|
||
|
if (!(d2 = v2->vdim))
|
||
|
if (cp1->Const.ci == 1)
|
||
|
continue;
|
||
|
else
|
||
|
return NO;
|
||
|
if (!(cp2 = (Constp)d2->nelt) || cp2->tag != TCONST
|
||
|
|| cp1->Const.ci != cp2->Const.ci)
|
||
|
return NO;
|
||
|
}
|
||
|
else if ((d2 = v2->vdim) && (!(cp2 = (Constp)d2->nelt)
|
||
|
|| cp2->tag != TCONST
|
||
|
|| cp2->Const.ci != 1))
|
||
|
return NO;
|
||
|
} /* while s1 != CHNULL && s2 != CHNULL */
|
||
|
|
||
|
return s1 == CHNULL && s2 == CHNULL;
|
||
|
} /* struct_eq */
|