1041 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1041 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 */
 |