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 */
 |