home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- Copyright 1990, 1991 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 "output.h"
- #include "names.h"
-
- LOCAL void conspower(), consbinop(), zdiv();
- LOCAL expptr fold(), mkpower(), stfcall();
- #ifndef stfcall_MAX
- #define stfcall_MAX 144
- #endif
-
- typedef struct { double dreal, dimag; } dcomplex;
-
- extern char dflttype[26];
-
- /* little routines to create constant blocks */
-
- Constp mkconst(t)
- register int t;
- {
- register Constp p;
-
- p = ALLOC(Constblock);
- p->tag = TCONST;
- p->vtype = t;
- return(p);
- }
-
-
- /* mklogcon -- Make Logical Constant */
-
- expptr mklogcon(l)
- register int l;
- {
- register Constp p;
-
- p = mkconst(TYLOGICAL);
- p->Const.ci = l;
- return( (expptr) p );
- }
-
-
-
- /* mkintcon -- Make Integer Constant */
-
- expptr mkintcon(l)
- ftnint l;
- {
- register Constp p;
-
- p = mkconst(tyint);
- p->Const.ci = l;
- return( (expptr) p );
- }
-
-
-
-
- /* mkaddcon -- Make Address Constant, given integer value */
-
- expptr mkaddcon(l)
- register long l;
- {
- register Constp p;
-
- p = mkconst(TYADDR);
- p->Const.ci = l;
- return( (expptr) p );
- }
-
-
-
- /* mkrealcon -- Make Real Constant. The type t is assumed
- to be TYREAL or TYDREAL */
-
- expptr mkrealcon(t, d)
- register int t;
- char *d;
- {
- register Constp p;
-
- p = mkconst(t);
- p->Const.cds[0] = cds(d,CNULL);
- p->vstg = 1;
- return( (expptr) p );
- }
-
-
- /* mkbitcon -- Make bit constant. Reads the input string, which is
- assumed to correctly specify a number in base 2^shift (where shift
- is the input parameter). shift may not exceed 4, i.e. only binary,
- quad, octal and hex bases may be input. Constants may not exceed 32
- bits, or whatever the size of (struct Constblock).ci may be. */
-
- expptr mkbitcon(shift, leng, s)
- int shift;
- int leng;
- char *s;
- {
- register Constp p;
- register long x;
-
- p = mkconst(TYLONG);
- x = 0;
- while(--leng >= 0)
- if(*s != ' ')
- x = (x << shift) | hextoi(*s++);
- /* mwm wanted to change the type to short for short constants,
- * but this is dangerous -- there is no syntax for long constants
- * with small values.
- */
- p->Const.ci = x;
- return( (expptr) p );
- }
-
-
-
-
-
- /* mkstrcon -- Make string constant. Allocates storage and initializes
- the memory for a copy of the input Fortran-string. */
-
- expptr mkstrcon(l,v)
- int l;
- register char *v;
- {
- register Constp p;
- register char *s;
-
- p = mkconst(TYCHAR);
- p->vleng = ICON(l);
- p->Const.ccp = s = (char *) ckalloc(l+1);
- p->Const.ccp1.blanks = 0;
- while(--l >= 0)
- *s++ = *v++;
- *s = '\0';
- return( (expptr) p );
- }
-
-
-
- /* mkcxcon -- Make complex contsant. A complex number is a pair of
- values, each of which may be integer, real or double. */
-
- expptr mkcxcon(realp,imagp)
- register expptr realp, imagp;
- {
- int rtype, itype;
- register Constp p;
- expptr errnode();
-
- rtype = realp->headblock.vtype;
- itype = imagp->headblock.vtype;
-
- if( ISCONST(realp) && ISNUMERIC(rtype) && ISCONST(imagp) && ISNUMERIC(itype) )
- {
- p = mkconst( (rtype==TYDREAL||itype==TYDREAL)
- ? TYDCOMPLEX : TYCOMPLEX);
- if (realp->constblock.vstg || imagp->constblock.vstg) {
- p->vstg = 1;
- p->Const.cds[0] = ISINT(rtype)
- ? string_num("", realp->constblock.Const.ci)
- : realp->constblock.vstg
- ? realp->constblock.Const.cds[0]
- : dtos(realp->constblock.Const.cd[0]);
- p->Const.cds[1] = ISINT(itype)
- ? string_num("", imagp->constblock.Const.ci)
- : imagp->constblock.vstg
- ? imagp->constblock.Const.cds[0]
- : dtos(imagp->constblock.Const.cd[0]);
- }
- else {
- p->Const.cd[0] = ISINT(rtype)
- ? realp->constblock.Const.ci
- : realp->constblock.Const.cd[0];
- p->Const.cd[1] = ISINT(itype)
- ? imagp->constblock.Const.ci
- : imagp->constblock.Const.cd[0];
- }
- }
- else
- {
- err("invalid complex constant");
- p = (Constp)errnode();
- }
-
- frexpr(realp);
- frexpr(imagp);
- return( (expptr) p );
- }
-
-
- /* errnode -- Allocate a new error block */
-
- expptr errnode()
- {
- struct Errorblock *p;
- p = ALLOC(Errorblock);
- p->tag = TERROR;
- p->vtype = TYERROR;
- return( (expptr) p );
- }
-
-
-
-
-
- /* mkconv -- Make type conversion. Cast expression p into type t.
- Note that casting to a character copies only the first sizeof(char)
- bytes. */
-
- expptr mkconv(t, p)
- register int t;
- register expptr p;
- {
- register expptr q;
- register int pt;
- expptr opconv();
-
- if(t==TYUNKNOWN || t==TYERROR)
- badtype("mkconv", t);
- pt = p->headblock.vtype;
-
- /* Casting to the same type is a no-op */
-
- if(t == pt)
- return(p);
-
- /* If we're casting a constant which is not in the literal table ... */
-
- else if( ISCONST(p) && pt!=TYADDR)
- {
- if (ISINT(t) && ISINT(pt) || ISREAL(t) && ISREAL(pt)) {
- /* avoid trouble with -i2 */
- p->headblock.vtype = t;
- return p;
- }
- q = (expptr) mkconst(t);
- consconv(t, &q->constblock, &p->constblock );
- frexpr(p);
- }
- else
- q = opconv(p, t);
-
- if(t == TYCHAR)
- q->constblock.vleng = ICON(1);
- return(q);
- }
-
-
-
- /* opconv -- Convert expression p to type t using the main
- expression evaluator; returns an OPCONV expression, I think 14-jun-88 mwm */
-
- expptr opconv(p, t)
- expptr p;
- int t;
- {
- register expptr q;
-
- q = mkexpr(OPCONV, p, ENULL);
- q->headblock.vtype = t;
- return(q);
- }
-
-
-
- /* addrof -- Create an ADDR expression operation */
-
- expptr addrof(p)
- expptr p;
- {
- return( mkexpr(OPADDR, p, ENULL) );
- }
-
-
-
- /* cpexpr - Returns a new copy of input expression p */
-
- tagptr cpexpr(p)
- register tagptr p;
- {
- register tagptr e;
- int tag;
- register chainp ep, pp;
- tagptr cpblock();
-
- /* This table depends on the ordering of the T macros, e.g. TNAME */
-
- static int blksize[ ] =
- {
- 0,
- sizeof(struct Nameblock),
- sizeof(struct Constblock),
- sizeof(struct Exprblock),
- sizeof(struct Addrblock),
- sizeof(struct Primblock),
- sizeof(struct Listblock),
- sizeof(struct Impldoblock),
- sizeof(struct Errorblock)
- };
-
- if(p == NULL)
- return(NULL);
-
- /* TNAMEs are special, and don't get copied. Each name in the current
- symbol table has a unique TNAME structure. */
-
- if( (tag = p->tag) == TNAME)
- return(p);
-
- e = cpblock(blksize[p->tag], (char *)p);
-
- switch(tag)
- {
- case TCONST:
- if(e->constblock.vtype == TYCHAR)
- {
- e->constblock.Const.ccp =
- copyn((int)e->constblock.vleng->constblock.Const.ci+1,
- e->constblock.Const.ccp);
- e->constblock.vleng =
- (expptr) cpexpr(e->constblock.vleng);
- }
- case TERROR:
- break;
-
- case TEXPR:
- e->exprblock.leftp = (expptr) cpexpr(p->exprblock.leftp);
- e->exprblock.rightp = (expptr) cpexpr(p->exprblock.rightp);
- break;
-
- case TLIST:
- if(pp = p->listblock.listp)
- {
- ep = e->listblock.listp =
- mkchain((char *)cpexpr((tagptr)pp->datap), CHNULL);
- for(pp = pp->nextp ; pp ; pp = pp->nextp)
- ep = ep->nextp =
- mkchain((char *)cpexpr((tagptr)pp->datap),
- CHNULL);
- }
- break;
-
- case TADDR:
- e->addrblock.vleng = (expptr) cpexpr(e->addrblock.vleng);
- e->addrblock.memoffset = (expptr)cpexpr(e->addrblock.memoffset);
- e->addrblock.istemp = NO;
- break;
-
- case TPRIM:
- e->primblock.argsp = (struct Listblock *)
- cpexpr((expptr)e->primblock.argsp);
- e->primblock.fcharp = (expptr) cpexpr(e->primblock.fcharp);
- e->primblock.lcharp = (expptr) cpexpr(e->primblock.lcharp);
- break;
-
- default:
- badtag("cpexpr", tag);
- }
-
- return(e);
- }
-
- /* frexpr -- Free expression -- frees up memory used by expression p */
-
- frexpr(p)
- register tagptr p;
- {
- register chainp q;
-
- if(p == NULL)
- return;
-
- switch(p->tag)
- {
- case TCONST:
- if( ISCHAR(p) )
- {
- free( (charptr) (p->constblock.Const.ccp) );
- frexpr(p->constblock.vleng);
- }
- break;
-
- case TADDR:
- if (p->addrblock.vtype > TYERROR) /* i/o block */
- break;
- frexpr(p->addrblock.vleng);
- frexpr(p->addrblock.memoffset);
- break;
-
- case TERROR:
- break;
-
- /* TNAME blocks don't get free'd - probably because they're pointed to in
- the hash table. 14-Jun-88 -- mwm */
-
- case TNAME:
- return;
-
- case TPRIM:
- frexpr((expptr)p->primblock.argsp);
- frexpr(p->primblock.fcharp);
- frexpr(p->primblock.lcharp);
- break;
-
- case TEXPR:
- frexpr(p->exprblock.leftp);
- if(p->exprblock.rightp)
- frexpr(p->exprblock.rightp);
- break;
-
- case TLIST:
- for(q = p->listblock.listp ; q ; q = q->nextp)
- frexpr((tagptr)q->datap);
- frchain( &(p->listblock.listp) );
- break;
-
- default:
- badtag("frexpr", p->tag);
- }
-
- free( (charptr) p );
- }
-
- void
- wronginf(np)
- Namep np;
- {
- int c, k;
- warn1("fixing wrong type inferred for %.65s", np->fvarname);
- np->vinftype = 0;
- c = letter(np->fvarname[0]);
- if ((np->vtype = impltype[c]) == TYCHAR
- && (k = implleng[c]))
- np->vleng = ICON(k);
- }
-
- /* fix up types in expression; replace subtrees and convert
- names to address blocks */
-
- expptr fixtype(p)
- register tagptr p;
- {
-
- if(p == 0)
- return(0);
-
- switch(p->tag)
- {
- case TCONST:
- if(ONEOF(p->constblock.vtype,MSKINT|MSKLOGICAL|MSKADDR|
- MSKREAL) )
- return( (expptr) p);
-
- return( (expptr) putconst((Constp)p) );
-
- case TADDR:
- p->addrblock.memoffset = fixtype(p->addrblock.memoffset);
- return( (expptr) p);
-
- case TERROR:
- return( (expptr) p);
-
- default:
- badtag("fixtype", p->tag);
-
- /* This case means that fixexpr can't call fixtype with any expr,
- only a subexpr of its parameter. */
-
- case TEXPR:
- return( fixexpr((Exprp)p) );
-
- case TLIST:
- return( (expptr) p );
-
- case TPRIM:
- if(p->primblock.argsp && p->primblock.namep->vclass!=CLVAR)
- {
- if(p->primblock.namep->vtype == TYSUBR)
- {
- err("function invocation of subroutine");
- return( errnode() );
- }
- else {
- if (p->primblock.namep->vinftype)
- wronginf(p->primblock.namep);
- return( mkfunct(p) );
- }
- }
-
- /* The lack of args makes p a function name, substring reference
- or variable name. */
-
- else return( mklhs((struct Primblock *) p) );
- }
- }
-
-
- static expptr
- cplenexpr(p)
- expptr p;
- {
- expptr rv;
-
- rv = cpexpr(p->headblock.vleng);
- if (ISCONST(p) && p->constblock.vtype == TYCHAR)
- rv->constblock.Const.ci += p->constblock.Const.ccp1.blanks;
- return rv;
- }
-
-
- /* special case tree transformations and cleanups of expression trees.
- Parameter p should have a TEXPR tag at its root, else an error is
- returned */
-
- expptr fixexpr(p)
- register Exprp p;
- {
- expptr lp;
- register expptr rp;
- register expptr q;
- int opcode, ltype, rtype, ptype, mtype;
-
- if( ISERROR(p) )
- return( (expptr) p );
- else if(p->tag != TEXPR)
- badtag("fixexpr", p->tag);
- opcode = p->opcode;
-
- /* First set the types of the left and right subexpressions */
-
- lp = p->leftp;
- if (!ISCONST(lp) || lp->constblock.vtype != TYCHAR)
- lp = p->leftp = fixtype(lp);
- ltype = lp->headblock.vtype;
-
- if(opcode==OPASSIGN && lp->tag!=TADDR)
- {
- err("left side of assignment must be variable");
- frexpr((expptr)p);
- return( errnode() );
- }
-
- if(rp = p->rightp)
- {
- if (!ISCONST(rp) || rp->constblock.vtype != TYCHAR)
- rp = p->rightp = fixtype(rp);
- rtype = rp->headblock.vtype;
- }
- else
- rtype = 0;
-
- if(ltype==TYERROR || rtype==TYERROR)
- {
- frexpr((expptr)p);
- return( errnode() );
- }
-
- /* Now work on the whole expression */
-
- /* force folding if possible */
-
- if( ISCONST(lp) && (rp==NULL || ISCONST(rp)) )
- {
- q = opcode == OPCONV && lp->constblock.vtype == p->vtype
- ? lp : mkexpr(opcode, lp, rp);
-
- /* mkexpr is expected to reduce constant expressions */
-
- if( ISCONST(q) ) {
- p->leftp = p->rightp = 0;
- frexpr(p);
- return(q);
- }
- free( (charptr) q ); /* constants did not fold */
- }
-
- if( (ptype = cktype(opcode, ltype, rtype)) == TYERROR)
- {
- frexpr((expptr)p);
- return( errnode() );
- }
-
- if (ltype == TYCHAR && ISCONST(lp))
- p->leftp = lp = (expptr)putconst((Constp)lp);
- if (rtype == TYCHAR && ISCONST(rp))
- p->rightp = rp = (expptr)putconst((Constp)rp);
-
- switch(opcode)
- {
- case OPCONCAT:
- if(p->vleng == NULL)
- p->vleng = mkexpr(OPPLUS, cplenexpr(lp),
- cplenexpr(rp) );
- break;
-
- case OPASSIGN:
- if (rtype == TYREAL)
- break;
- case OPPLUSEQ:
- case OPSTAREQ:
- if(ltype == rtype)
- break;
- if( ! ISCONST(rp) && ISREAL(ltype) && ISREAL(rtype) )
- break;
- if( ISCOMPLEX(ltype) || ISCOMPLEX(rtype) )
- break;
- if( ONEOF(ltype, MSKADDR|MSKINT) && ONEOF(rtype, MSKADDR|MSKINT)
- && typesize[ltype]>=typesize[rtype] )
- break;
-
- /* Cast the right hand side to match the type of the expression */
-
- p->rightp = fixtype( mkconv(ptype, rp) );
- break;
-
- case OPSLASH:
- if( ISCOMPLEX(rtype) )
- {
- p = (Exprp) call2(ptype,
-
- /* Handle double precision complex variables */
-
- ptype == TYCOMPLEX ? "c_div" : "z_div",
- mkconv(ptype, lp), mkconv(ptype, rp) );
- break;
- }
- case OPPLUS:
- case OPMINUS:
- case OPSTAR:
- case OPMOD:
- if(ptype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp) ) ||
- (rtype==TYREAL && ! ISCONST(rp) ) ))
- break;
- if( ISCOMPLEX(ptype) )
- break;
-
- /* Cast both sides of the expression to match the type of the whole
- expression. */
-
- if(ltype != ptype && (ltype < TYSHORT || ptype > TYDREAL))
- p->leftp = fixtype(mkconv(ptype,lp));
- if(rtype != ptype && (rtype < TYSHORT || ptype > TYDREAL))
- p->rightp = fixtype(mkconv(ptype,rp));
- break;
-
- case OPPOWER:
- return( mkpower((expptr)p) );
-
- case OPLT:
- case OPLE:
- case OPGT:
- case OPGE:
- case OPEQ:
- case OPNE:
- if(ltype == rtype)
- break;
- mtype = cktype(OPMINUS, ltype, rtype);
- if(mtype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp)) ||
- (rtype==TYREAL && ! ISCONST(rp)) ))
- break;
- if( ISCOMPLEX(mtype) )
- break;
- if(ltype != mtype)
- p->leftp = fixtype(mkconv(mtype,lp));
- if(rtype != mtype)
- p->rightp = fixtype(mkconv(mtype,rp));
- break;
-
- case OPCONV:
- ptype = cktype(OPCONV, p->vtype, ltype);
- if(lp->tag==TEXPR && lp->exprblock.opcode==OPCOMMA)
- {
- lp->exprblock.rightp =
- fixtype( mkconv(ptype, lp->exprblock.rightp) );
- free( (charptr) p );
- p = (Exprp) lp;
- }
- break;
-
- case OPADDR:
- if(lp->tag==TEXPR && lp->exprblock.opcode==OPADDR)
- Fatal("addr of addr");
- break;
-
- case OPCOMMA:
- case OPQUEST:
- case OPCOLON:
- break;
-
- case OPMIN:
- case OPMAX:
- case OPMIN2:
- case OPMAX2:
- case OPDMIN:
- case OPDMAX:
- case OPABS:
- case OPDABS:
- ptype = p->vtype;
- break;
-
- default:
- break;
- }
-
- p->vtype = ptype;
- return((expptr) p);
- }
-
-
- /* fix an argument list, taking due care for special first level cases */
-
- fixargs(doput, p0)
- int doput; /* doput is true if constants need to be passed by reference */
- struct Listblock *p0;
- {
- register chainp p;
- register tagptr q, t;
- register int qtag;
- int nargs;
- Addrp mkscalar();
-
- nargs = 0;
- if(p0)
- for(p = p0->listp ; p ; p = p->nextp)
- {
- ++nargs;
- q = (tagptr)p->datap;
- qtag = q->tag;
- if(qtag == TCONST)
- {
-
- /* Call putconst() to store values in a constant table. Since even
- constants must be passed by reference, this can optimize on the storage
- required */
-
- p->datap = doput ? (char *)putconst((Constp)q)
- : (char *)q;
- }
-
- /* Take a function name and turn it into an Addr. This only happens when
- nothing else has figured out the function beforehand */
-
- else if(qtag==TPRIM && q->primblock.argsp==0 &&
- q->primblock.namep->vclass==CLPROC &&
- q->primblock.namep->vprocclass != PTHISPROC)
- p->datap = (char *)mkaddr(q->primblock.namep);
-
- else if(qtag==TPRIM && q->primblock.argsp==0 &&
- q->primblock.namep->vdim!=NULL)
- p->datap = (char *)mkscalar(q->primblock.namep);
-
- else if(qtag==TPRIM && q->primblock.argsp==0 &&
- q->primblock.namep->vdovar &&
- (t = (tagptr) memversion(q->primblock.namep)) )
- p->datap = (char *)fixtype(t);
- else
- p->datap = (char *)fixtype(q);
- }
- return(nargs);
- }
-
-
-
- /* mkscalar -- only called by fixargs above, and by some routines in
- io.c */
-
- Addrp mkscalar(np)
- register Namep np;
- {
- register Addrp ap;
-
- vardcl(np);
- ap = mkaddr(np);
-
- /* The prolog causes array arguments to point to the
- * (0,...,0) element, unless subscript checking is on.
- */
- if( !checksubs && np->vstg==STGARG)
- {
- register struct Dimblock *dp;
- dp = np->vdim;
- frexpr(ap->memoffset);
- ap->memoffset = mkexpr(OPSTAR,
- (np->vtype==TYCHAR ?
- cpexpr(np->vleng) :
- (tagptr)ICON(typesize[np->vtype]) ),
- cpexpr(dp->baseoffset) );
- }
- return(ap);
- }
-
-
- static void
- adjust_arginfo(np) /* adjust arginfo to omit the length arg for the
- arg that we now know to be a character-valued
- function */
- register Namep np;
- {
- struct Entrypoint *ep;
- register chainp args;
- Argtypes *at;
-
- for(ep = entries; ep; ep = ep->entnextp)
- for(args = ep->arglist; args; args = args->nextp)
- if (np == (Namep)args->datap
- && (at = ep->entryname->arginfo))
- --at->nargs;
- }
-
-
-
- expptr mkfunct(p0)
- expptr p0;
- {
- register struct Primblock *p = (struct Primblock *)p0;
- struct Entrypoint *ep;
- Addrp ap;
- Extsym *extp;
- register Namep np;
- register expptr q;
- expptr intrcall();
- extern chainp new_procs;
- int k, nargs;
- int class;
-
- if(p->tag != TPRIM)
- return( errnode() );
-
- np = p->namep;
- class = np->vclass;
-
-
- if(class == CLUNKNOWN)
- {
- np->vclass = class = CLPROC;
- if(np->vstg == STGUNKNOWN)
- {
- if(np->vtype!=TYSUBR && (k = intrfunct(np->fvarname))
- && (zflag || !(*(struct Intrpacked *)&k).f4
- || dcomplex_seen))
- {
- np->vstg = STGINTR;
- np->vardesc.varno = k;
- np->vprocclass = PINTRINSIC;
- }
- else
- {
- extp = mkext(np->fvarname,
- addunder(np->cvarname));
- extp->extstg = STGEXT;
- np->vstg = STGEXT;
- np->vardesc.varno = extp - extsymtab;
- np->vprocclass = PEXTERNAL;
- }
- }
- else if(np->vstg==STGARG)
- {
- if(np->vtype == TYCHAR) {
- adjust_arginfo(np);
- if (np->vpassed) {
- char wbuf[160], *who;
- who = np->fvarname;
- sprintf(wbuf, "%s%s%s\n\t%s%s%s",
- "Character-valued dummy procedure ",
- who, " not declared EXTERNAL.",
- "Code may be wrong for previous function calls having ",
- who, " as a parameter.");
- warn(wbuf);
- }
- }
- np->vprocclass = PEXTERNAL;
- }
- }
-
- if(class != CLPROC)
- fatali("invalid class code %d for function", class);
-
- /* F77 doesn't allow subscripting of function calls */
-
- if(p->fcharp || p->lcharp)
- {
- err("no substring of function call");
- goto error;
- }
- impldcl(np);
- np->vimpltype = 0; /* invoking as function ==> inferred type */
- np->vcalled = 1;
- nargs = fixargs( np->vprocclass!=PINTRINSIC, p->argsp);
-
- switch(np->vprocclass)
- {
- case PEXTERNAL:
- if(np->vtype == TYUNKNOWN)
- {
- dclerr("attempt to use untyped function", np);
- np->vtype = dflttype[letter(np->fvarname[0])];
- }
- ap = mkaddr(np);
- if (!extsymtab[np->vardesc.varno].extseen) {
- new_procs = mkchain((char *)np, new_procs);
- extsymtab[np->vardesc.varno].extseen = 1;
- }
- call:
- q = mkexpr(OPCALL, (expptr)ap, (expptr)p->argsp);
- q->exprblock.vtype = np->vtype;
- if(np->vleng)
- q->exprblock.vleng = (expptr) cpexpr(np->vleng);
- break;
-
- case PINTRINSIC:
- q = intrcall(np, p->argsp, nargs);
- break;
-
- case PSTFUNCT:
- q = stfcall(np, p->argsp);
- break;
-
- case PTHISPROC:
- warn("recursive call");
-
- /* entries is the list of multiple entry points */
-
- for(ep = entries ; ep ; ep = ep->entnextp)
- if(ep->enamep == np)
- break;
- if(ep == NULL)
- Fatal("mkfunct: impossible recursion");
-
- ap = builtin(np->vtype, ep->entryname->cextname, -2);
- /* the negative last arg prevents adding */
- /* this name to the list of used builtins */
- goto call;
-
- default:
- fatali("mkfunct: impossible vprocclass %d",
- (int) (np->vprocclass) );
- }
- free( (charptr) p );
- return(q);
-
- error:
- frexpr((expptr)p);
- return( errnode() );
- }
-
-
-
- LOCAL expptr stfcall(np, actlist)
- Namep np;
- struct Listblock *actlist;
- {
- register chainp actuals;
- int nargs;
- chainp oactp, formals;
- int type;
- expptr Ln, Lq, q, q1, rhs, ap;
- Namep tnp;
- register struct Rplblock *rp;
- struct Rplblock *tlist;
- static int inv_count;
-
- if (++inv_count > stfcall_MAX)
- Fatal("Loop invoking recursive statement function?");
- if(actlist)
- {
- actuals = actlist->listp;
- free( (charptr) actlist);
- }
- else
- actuals = NULL;
- oactp = actuals;
-
- nargs = 0;
- tlist = NULL;
- if( (type = np->vtype) == TYUNKNOWN)
- {
- dclerr("attempt to use untyped statement function", np);
- type = np->vtype = dflttype[letter(np->fvarname[0])];
- }
- formals = (chainp) np->varxptr.vstfdesc->datap;
- rhs = (expptr) (np->varxptr.vstfdesc->nextp);
-
- /* copy actual arguments into temporaries */
- while(actuals!=NULL && formals!=NULL)
- {
- rp = ALLOC(Rplblock);
- rp->rplnp = tnp = (Namep) formals->datap;
- ap = fixtype((tagptr)actuals->datap);
- if(tnp->vtype==ap->headblock.vtype && tnp->vtype!=TYCHAR
- && (ap->tag==TCONST || ap->tag==TADDR) )
- {
-
- /* If actuals are constants or variable names, no temporaries are required */
- rp->rplvp = (expptr) ap;
- rp->rplxp = NULL;
- rp->rpltag = ap->tag;
- }
- else {
- rp->rplvp = (expptr) mktmp(tnp->vtype, tnp->vleng);
- rp -> rplxp = NULL;
- putexpr ( mkexpr(OPASSIGN, cpexpr(rp->rplvp), ap));
- if((rp->rpltag = rp->rplvp->tag) == TERROR)
- err("disagreement of argument types in statement function call");
- }
- rp->rplnextp = tlist;
- tlist = rp;
- actuals = actuals->nextp;
- formals = formals->nextp;
- ++nargs;
- }
-
- if(actuals!=NULL || formals!=NULL)
- err("statement function definition and argument list differ");
-
- /*
- now push down names involved in formal argument list, then
- evaluate rhs of statement function definition in this environment
- */
-
- if(tlist) /* put tlist in front of the rpllist */
- {
- for(rp = tlist; rp->rplnextp; rp = rp->rplnextp)
- ;
- rp->rplnextp = rpllist;
- rpllist = tlist;
- }
-
- /* So when the expression finally gets evaled, that evaluator must read
- from the globl rpllist 14-jun-88 mwm */
-
- q = (expptr) mkconv(type, fixtype(cpexpr(rhs)) );
-
- /* get length right of character-valued statement functions... */
- if (type == TYCHAR
- && (Ln = np->vleng)
- && q->tag != TERROR
- && (Lq = q->exprblock.vleng)
- && (Lq->tag != TCONST
- || Ln->constblock.Const.ci != Lq->constblock.Const.ci)) {
- q1 = (expptr) mktmp(type, Ln);
- putexpr ( mkexpr(OPASSIGN, cpexpr(q1), q));
- q = q1;
- }
-
- /* now generate the tree ( t1=a1, (t2=a2,... , f))))) */
- while(--nargs >= 0)
- {
- if(rpllist->rplxp)
- q = mkexpr(OPCOMMA, rpllist->rplxp, q);
- rp = rpllist->rplnextp;
- frexpr(rpllist->rplvp);
- free((char *)rpllist);
- rpllist = rp;
- }
- frchain( &oactp );
- --inv_count;
- return(q);
- }
-
-
- static int replaced;
-
- /* mkplace -- Figure out the proper storage class for the input name and
- return an addrp with the appropriate stuff */
-
- Addrp mkplace(np)
- register Namep np;
- {
- register Addrp s;
- register struct Rplblock *rp;
- int regn;
-
- /* is name on the replace list? */
-
- for(rp = rpllist ; rp ; rp = rp->rplnextp)
- {
- if(np == rp->rplnp)
- {
- replaced = 1;
- if(rp->rpltag == TNAME)
- {
- np = (Namep) (rp->rplvp);
- break;
- }
- else return( (Addrp) cpexpr(rp->rplvp) );
- }
- }
-
- /* is variable a DO index in a register ? */
-
- if(np->vdovar && ( (regn = inregister(np)) >= 0) )
- if(np->vtype == TYERROR)
- return((Addrp) errnode() );
- else
- {
- s = ALLOC(Addrblock);
- s->tag = TADDR;
- s->vstg = STGREG;
- s->vtype = TYIREG;
- s->memno = regn;
- s->memoffset = ICON(0);
- s -> uname_tag = UNAM_NAME;
- s -> user.name = np;
- return(s);
- }
-
- vardcl(np);
- return(mkaddr(np));
- }
-
-
- static int doing_vleng;
-
- /* mklhs -- Compute the actual address of the given expression; account
- for array subscripts, stack offset, and substring offsets. The f -> C
- translator will need this only to worry about the subscript stuff */
-
- expptr mklhs(p)
- register struct Primblock *p;
- {
- expptr suboffset();
- register Addrp s;
- Namep np;
-
- if(p->tag != TPRIM)
- return( (expptr) p );
- np = p->namep;
-
- replaced = 0;
- s = mkplace(np);
- if(s->tag!=TADDR || s->vstg==STGREG)
- {
- free( (charptr) p );
- return( (expptr) s );
- }
-
- /* compute the address modified by subscripts */
-
- if (!replaced)
- s->memoffset = mkexpr(OPPLUS, s->memoffset, suboffset(p) );
- frexpr((expptr)p->argsp);
- p->argsp = NULL;
-
- /* now do substring part */
-
- if(p->fcharp || p->lcharp)
- {
- if(np->vtype != TYCHAR)
- errstr("substring of noncharacter %s", np->fvarname);
- else {
- if(p->lcharp == NULL)
- p->lcharp = (expptr) cpexpr(s->vleng);
- if(p->fcharp) {
- doing_vleng = 1;
- s->vleng = fixtype(mkexpr(OPMINUS,
- p->lcharp,
- mkexpr(OPMINUS, p->fcharp, ICON(1) )));
- doing_vleng = 0;
- }
- else {
- frexpr(s->vleng);
- s->vleng = p->lcharp;
- }
- }
- }
-
- s->vleng = fixtype( s->vleng );
- s->memoffset = fixtype( s->memoffset );
- free( (charptr) p );
- return( (expptr) s );
- }
-
-
-
-
-
- /* deregister -- remove a register allocation from the list; assumes that
- names are deregistered in stack order (LIFO order - Last In First Out) */
-
- deregister(np)
- Namep np;
- {
- if(nregvar>0 && regnamep[nregvar-1]==np)
- {
- --nregvar;
- }
- }
-
-
-
-
- /* memversion -- moves a DO index REGISTER into a memory location; other
- objects are passed through untouched */
-
- Addrp memversion(np)
- register Namep np;
- {
- register Addrp s;
-
- if(np->vdovar==NO || (inregister(np)<0) )
- return(NULL);
- np->vdovar = NO;
- s = mkplace(np);
- np->vdovar = YES;
- return(s);
- }
-
-
-
- /* inregister -- looks for the input name in the global list regnamep */
-
- inregister(np)
- register Namep np;
- {
- register int i;
-
- for(i = 0 ; i < nregvar ; ++i)
- if(regnamep[i] == np)
- return( regnum[i] );
- return(-1);
- }
-
-
-
- /* suboffset -- Compute the offset from the start of the array, given the
- subscripts as arguments */
-
- expptr suboffset(p)
- register struct Primblock *p;
- {
- int n;
- expptr si, size;
- chainp cp;
- expptr e, e1, offp, prod;
- expptr subcheck();
- struct Dimblock *dimp;
- expptr sub[MAXDIM+1];
- register Namep np;
-
- np = p->namep;
- offp = ICON(0);
- n = 0;
- if(p->argsp)
- for(cp = p->argsp->listp ; cp ; cp = cp->nextp)
- {
- si = fixtype(cpexpr((tagptr)cp->datap));
- if (!ISINT(si->headblock.vtype)) {
- NOEXT("non-integer subscript");
- si = mkconv(TYLONG, si);
- }
- sub[n++] = si;
- if(n > maxdim)
- {
- erri("more than %d subscripts", maxdim);
- break;
- }
- }
-
- dimp = np->vdim;
- if(n>0 && dimp==NULL)
- errstr("subscripts on scalar variable %.68s", np->fvarname);
- else if(dimp && dimp->ndim!=n)
- errstr("wrong number of subscripts on %.68s", np->fvarname);
- else if(n > 0)
- {
- prod = sub[--n];
- while( --n >= 0)
- prod = mkexpr(OPPLUS, sub[n],
- mkexpr(OPSTAR, prod, cpexpr(dimp->dims[n].dimsize)) );
- if(checksubs || np->vstg!=STGARG)
- prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset));
-
- /* Add in the run-time bounds check */
-
- if(checksubs)
- prod = subcheck(np, prod);
- size = np->vtype == TYCHAR ?
- (expptr) cpexpr(np->vleng) : ICON(typesize[np->vtype]);
- prod = mkexpr(OPSTAR, prod, size);
- offp = mkexpr(OPPLUS, offp, prod);
- }
-
- /* Check for substring indicator */
-
- if(p->fcharp && np->vtype==TYCHAR) {
- e = p->fcharp;
- e1 = mkexpr(OPMINUS, cpexpr(e), ICON(1));
- if (!ISCONST(e) && (e->tag != TPRIM || e->primblock.argsp)) {
- e = (expptr)mktmp(TYLONG, ENULL);
- putout(putassign(cpexpr(e), e1));
- p->fcharp = mkexpr(OPPLUS, cpexpr(e), ICON(1));
- e1 = e;
- }
- offp = mkexpr(OPPLUS, offp, e1);
- }
- return(offp);
- }
-
-
-
-
- expptr subcheck(np, p)
- Namep np;
- register expptr p;
- {
- struct Dimblock *dimp;
- expptr t, checkvar, checkcond, badcall;
-
- dimp = np->vdim;
- if(dimp->nelt == NULL)
- return(p); /* don't check arrays with * bounds */
- np->vlastdim = 0;
- if( ISICON(p) )
- {
-
- /* check for negative (constant) offset */
-
- if(p->constblock.Const.ci < 0)
- goto badsub;
- if( ISICON(dimp->nelt) )
-
- /* see if constant offset exceeds the array declaration */
-
- if(p->constblock.Const.ci < dimp->nelt->constblock.Const.ci)
- return(p);
- else
- goto badsub;
- }
-
- /* We know that the subscript offset p or dimp -> nelt is not a constant.
- Now find a register to use for run-time bounds checking */
-
- if(p->tag==TADDR && p->addrblock.vstg==STGREG)
- {
- checkvar = (expptr) cpexpr(p);
- t = p;
- }
- else {
- checkvar = (expptr) mktmp(p->headblock.vtype, ENULL);
- t = mkexpr(OPASSIGN, cpexpr(checkvar), p);
- }
- checkcond = mkexpr(OPLT, t, cpexpr(dimp->nelt) );
- if( ! ISICON(p) )
- checkcond = mkexpr(OPAND, checkcond,
- mkexpr(OPLE, ICON(0), cpexpr(checkvar)) );
-
- /* Construct the actual test */
-
- badcall = call4(p->headblock.vtype, "s_rnge",
- mkstrcon(strlen(np->fvarname), np->fvarname),
- mkconv(TYLONG, cpexpr(checkvar)),
- mkstrcon(strlen(procname), procname),
- ICON(lineno) );
- badcall->exprblock.opcode = OPCCALL;
- p = mkexpr(OPQUEST, checkcond,
- mkexpr(OPCOLON, checkvar, badcall));
-
- return(p);
-
- badsub:
- frexpr(p);
- errstr("subscript on variable %s out of range", np->fvarname);
- return ( ICON(0) );
- }
-
-
-
-
- Addrp mkaddr(p)
- register Namep p;
- {
- Extsym *extp;
- register Addrp t;
- Addrp intraddr();
- int k;
-
- switch( p->vstg)
- {
- case STGAUTO:
- if(p->vclass == CLPROC && p->vprocclass == PTHISPROC)
- return (Addrp) cpexpr((expptr)xretslot[p->vtype]);
- goto other;
-
- case STGUNKNOWN:
- if(p->vclass != CLPROC)
- break; /* Error */
- extp = mkext(p->fvarname, addunder(p->cvarname));
- extp->extstg = STGEXT;
- p->vstg = STGEXT;
- p->vardesc.varno = extp - extsymtab;
- p->vprocclass = PEXTERNAL;
- if ((extp->exproto || infertypes)
- && (p->vtype == TYUNKNOWN || p->vimpltype)
- && (k = extp->extype))
- inferdcl(p, k);
-
-
- case STGCOMMON:
- case STGEXT:
- case STGBSS:
- case STGINIT:
- case STGEQUIV:
- case STGARG:
- case STGLENG:
- other:
- t = ALLOC(Addrblock);
- t->tag = TADDR;
-
- t->vclass = p->vclass;
- t->vtype = p->vtype;
- t->vstg = p->vstg;
- t->memno = p->vardesc.varno;
- t->memoffset = ICON(p->voffset);
- if (p->vdim)
- t->isarray = 1;
- if(p->vleng)
- {
- t->vleng = (expptr) cpexpr(p->vleng);
- if( ISICON(t->vleng) )
- t->varleng = t->vleng->constblock.Const.ci;
- }
-
- /* Keep the original name around for the C code generation */
-
- t -> uname_tag = UNAM_NAME;
- t -> user.name = p;
- return(t);
-
- case STGINTR:
-
- return ( intraddr (p));
- }
- badstg("mkaddr", p->vstg);
- /* NOT REACHED */ return 0;
- }
-
-
-
-
- /* mkarg -- create storage for a new parameter. This is called when a
- function returns a string (for the return value, which is the first
- parameter), or when a variable-length string is passed to a function. */
-
- Addrp mkarg(type, argno)
- int type, argno;
- {
- register Addrp p;
-
- p = ALLOC(Addrblock);
- p->tag = TADDR;
- p->vtype = type;
- p->vclass = CLVAR;
-
- /* TYLENG is the type of the field holding the length of a character string */
-
- p->vstg = (type==TYLENG ? STGLENG : STGARG);
- p->memno = argno;
- return(p);
- }
-
-
-
-
- /* mkprim -- Create a PRIM (primary/primitive) block consisting of a
- Nameblock (or Paramblock), arguments (actual params or array
- subscripts) and substring bounds. Requires that v have lots of
- extra (uninitialized) storage, since it could be a paramblock or
- nameblock */
-
- expptr mkprim(v0, args, substr)
- Namep v0;
- struct Listblock *args;
- chainp substr;
- {
- typedef union {
- struct Paramblock paramblock;
- struct Nameblock nameblock;
- struct Headblock headblock;
- } *Primu;
- register Primu v = (Primu)v0;
- register struct Primblock *p;
-
- if(v->headblock.vclass == CLPARAM)
- {
-
- /* v is to be a Paramblock */
-
- if(args || substr)
- {
- errstr("no qualifiers on parameter name %s",
- v->paramblock.fvarname);
- frexpr((expptr)args);
- if(substr)
- {
- frexpr((tagptr)substr->datap);
- frexpr((tagptr)substr->nextp->datap);
- frchain(&substr);
- }
- frexpr((expptr)v);
- return( errnode() );
- }
- return( (expptr) cpexpr(v->paramblock.paramval) );
- }
-
- p = ALLOC(Primblock);
- p->tag = TPRIM;
- p->vtype = v->nameblock.vtype;
-
- /* v is to be a Nameblock */
-
- p->namep = (Namep) v;
- p->argsp = args;
- if(substr)
- {
- p->fcharp = (expptr) substr->datap;
- p->lcharp = (expptr) substr->nextp->datap;
- frchain(&substr);
- }
- return( (expptr) p);
- }
-
-
-
- /* vardcl -- attempt to fill out the Name template for variable v.
- This function is called on identifiers known to be variables or
- recursive references to the same function */
-
- vardcl(v)
- register Namep v;
- {
- struct Dimblock *t;
- expptr neltp;
- extern int doing_stmtfcn;
-
- if(v->vclass == CLUNKNOWN) {
- v->vclass = CLVAR;
- if (v->vinftype) {
- v->vtype = TYUNKNOWN;
- if (v->vdcldone) {
- v->vdcldone = 0;
- impldcl(v);
- }
- }
- }
- if(v->vdcldone)
- return;
- if(v->vclass == CLNAMELIST)
- return;
-
- if(v->vtype == TYUNKNOWN)
- impldcl(v);
- else if(v->vclass!=CLVAR && v->vprocclass!=PTHISPROC)
- {
- dclerr("used as variable", v);
- return;
- }
- if(v->vstg==STGUNKNOWN) {
- if (doing_stmtfcn) {
- /* neither declare this variable if its only use */
- /* is in defining a stmt function, nor complain */
- /* that it is never used */
- v->vimpldovar = 1;
- return;
- }
- v->vstg = implstg[ letter(v->fvarname[0]) ];
- v->vimplstg = 1;
- }
-
- /* Compute the actual storage location, i.e. offsets from base addresses,
- possibly the stack pointer */
-
- switch(v->vstg)
- {
- case STGBSS:
- v->vardesc.varno = ++lastvarno;
- break;
- case STGAUTO:
- if(v->vclass==CLPROC && v->vprocclass==PTHISPROC)
- break;
- if(t = v->vdim)
- if( (neltp = t->nelt) && ISCONST(neltp) ) ;
- else
- dclerr("adjustable automatic array", v);
- break;
-
- default:
- break;
- }
- v->vdcldone = YES;
- }
-
-
-
- /* Set the implicit type declaration of parameter p based on its first
- letter */
-
- impldcl(p)
- register Namep p;
- {
- register int k;
- int type;
- ftnint leng;
-
- if(p->vdcldone || (p->vclass==CLPROC && p->vprocclass==PINTRINSIC) )
- return;
- if(p->vtype == TYUNKNOWN)
- {
- k = letter(p->fvarname[0]);
- type = impltype[ k ];
- leng = implleng[ k ];
- if(type == TYUNKNOWN)
- {
- if(p->vclass == CLPROC)
- return;
- dclerr("attempt to use undefined variable", p);
- type = dflttype[k];
- leng = 0;
- }
- settype(p, type, leng);
- p->vimpltype = 1;
- }
- }
-
- void
- inferdcl(np,type)
- Namep np;
- int type;
- {
- int k = impltype[letter(np->fvarname[0])];
- if (k != type) {
- np->vinftype = 1;
- np->vtype = type;
- frexpr(np->vleng);
- np->vleng = 0;
- }
- np->vimpltype = 0;
- np->vinfproc = 1;
- }
-
-
- #define ICONEQ(z, c) (ISICON(z) && z->constblock.Const.ci==c)
- #define COMMUTE { e = lp; lp = rp; rp = e; }
-
-
-
- /* mkexpr -- Make expression, and simplify constant subcomponents (tree
- order is not preserved). Assumes that lp is nonempty, and uses
- fold() to simplify adjacent constants */
-
- expptr mkexpr(opcode, lp, rp)
- int opcode;
- register expptr lp, rp;
- {
- register expptr e, e1;
- int etype;
- int ltype, rtype;
- int ltag, rtag;
- long L;
-
- ltype = lp->headblock.vtype;
- ltag = lp->tag;
- if(rp && opcode!=OPCALL && opcode!=OPCCALL)
- {
- rtype = rp->headblock.vtype;
- rtag = rp->tag;
- }
- else rtype = 0;
-
- etype = cktype(opcode, ltype, rtype);
- if(etype == TYERROR)
- goto error;
-
- switch(opcode)
- {
- /* check for multiplication by 0 and 1 and addition to 0 */
-
- case OPSTAR:
- if( ISCONST(lp) )
- COMMUTE
-
- if( ISICON(rp) )
- {
- if(rp->constblock.Const.ci == 0)
- goto retright;
- goto mulop;
- }
- break;
-
- case OPSLASH:
- case OPMOD:
- if( ICONEQ(rp, 0) )
- {
- err("attempted division by zero");
- rp = ICON(1);
- break;
- }
- if(opcode == OPMOD)
- break;
-
- /* Handle multiplying or dividing by 1, -1 */
-
- mulop:
- if( ISICON(rp) )
- {
- if(rp->constblock.Const.ci == 1)
- goto retleft;
-
- if(rp->constblock.Const.ci == -1)
- {
- frexpr(rp);
- return( mkexpr(OPNEG, lp, ENULL) );
- }
- }
-
- /* Group all constants together. In particular,
-
- (x * CONST1) * CONST2 ==> x * (CONST1 * CONST2)
- (x * CONST1) / CONST2 ==> x * (CONST1 / CONST2)
- */
-
- if (lp->tag != TEXPR || !lp->exprblock.rightp
- || !ISICON(lp->exprblock.rightp))
- break;
-
- if (lp->exprblock.opcode == OPLSHIFT) {
- L = 1 << lp->exprblock.rightp->constblock.Const.ci;
- if (opcode == OPSTAR || ISICON(rp) &&
- !(L % rp->constblock.Const.ci)) {
- lp->exprblock.opcode = OPSTAR;
- lp->exprblock.rightp->constblock.Const.ci = L;
- }
- }
-
- if (lp->exprblock.opcode == OPSTAR) {
- if(opcode == OPSTAR)
- e = mkexpr(OPSTAR, lp->exprblock.rightp, rp);
- else if(ISICON(rp) &&
- (lp->exprblock.rightp->constblock.Const.ci %
- rp->constblock.Const.ci) == 0)
- e = mkexpr(OPSLASH, lp->exprblock.rightp, rp);
- else break;
-
- e1 = lp->exprblock.leftp;
- free( (charptr) lp );
- return( mkexpr(OPSTAR, e1, e) );
- }
- break;
-
-
- case OPPLUS:
- if( ISCONST(lp) )
- COMMUTE
- goto addop;
-
- case OPMINUS:
- if( ICONEQ(lp, 0) )
- {
- frexpr(lp);
- return( mkexpr(OPNEG, rp, ENULL) );
- }
-
- if( ISCONST(rp) && is_negatable((Constp)rp))
- {
- opcode = OPPLUS;
- consnegop((Constp)rp);
- }
-
- /* Group constants in an addition expression (also subtraction, since the
- subtracted value was negated above). In particular,
-
- (x + CONST1) + CONST2 ==> x + (CONST1 + CONST2)
- */
-
- addop:
- if( ISICON(rp) )
- {
- if(rp->constblock.Const.ci == 0)
- goto retleft;
- if( ISPLUSOP(lp) && ISICON(lp->exprblock.rightp) )
- {
- e = mkexpr(OPPLUS, lp->exprblock.rightp, rp);
- e1 = lp->exprblock.leftp;
- free( (charptr) lp );
- return( mkexpr(OPPLUS, e1, e) );
- }
- }
- if (opcode == OPMINUS && (ISINT(etype) || doing_vleng)) {
- /* check for (i [+const]) - (i [+const]) */
- if (lp->tag == TPRIM)
- e = lp;
- else if (lp->tag == TEXPR && lp->exprblock.opcode == OPPLUS
- && lp->exprblock.rightp->tag == TCONST) {
- e = lp->exprblock.leftp;
- if (e->tag != TPRIM)
- break;
- }
- else
- break;
- if (e->primblock.argsp)
- break;
- if (rp->tag == TPRIM)
- e1 = rp;
- else if (rp->tag == TEXPR && rp->exprblock.opcode == OPPLUS
- && rp->exprblock.rightp->tag == TCONST) {
- e1 = rp->exprblock.leftp;
- if (e1->tag != TPRIM)
- break;
- }
- else
- break;
- if (e->primblock.namep != e1->primblock.namep
- || e1->primblock.argsp)
- break;
- L = e == lp ? 0 : lp->exprblock.rightp->constblock.Const.ci;
- if (e1 != rp)
- L -= rp->exprblock.rightp->constblock.Const.ci;
- frexpr(lp);
- frexpr(rp);
- return ICON(L);
- }
-
- break;
-
-
- case OPPOWER:
- break;
-
- /* Eliminate outermost double negations */
-
- case OPNEG:
- case OPNEG1:
- if(ltag==TEXPR && lp->exprblock.opcode==OPNEG)
- {
- e = lp->exprblock.leftp;
- free( (charptr) lp );
- return(e);
- }
- break;
-
- /* Eliminate outermost double NOTs */
-
- case OPNOT:
- if(ltag==TEXPR && lp->exprblock.opcode==OPNOT)
- {
- e = lp->exprblock.leftp;
- free( (charptr) lp );
- return(e);
- }
- break;
-
- case OPCALL:
- case OPCCALL:
- etype = ltype;
- if(rp!=NULL && rp->listblock.listp==NULL)
- {
- free( (charptr) rp );
- rp = NULL;
- }
- break;
-
- case OPAND:
- case OPOR:
- if( ISCONST(lp) )
- COMMUTE
-
- if( ISCONST(rp) )
- {
- if(rp->constblock.Const.ci == 0)
- if(opcode == OPOR)
- goto retleft;
- else
- goto retright;
- else if(opcode == OPOR)
- goto retright;
- else
- goto retleft;
- }
- case OPEQV:
- case OPNEQV:
-
- case OPBITAND:
- case OPBITOR:
- case OPBITXOR:
- case OPBITNOT:
- case OPLSHIFT:
- case OPRSHIFT:
-
- case OPLT:
- case OPGT:
- case OPLE:
- case OPGE:
- case OPEQ:
- case OPNE:
-
- case OPCONCAT:
- break;
- case OPMIN:
- case OPMAX:
- case OPMIN2:
- case OPMAX2:
- case OPDMIN:
- case OPDMAX:
-
- case OPASSIGN:
- case OPASSIGNI:
- case OPPLUSEQ:
- case OPSTAREQ:
- case OPMINUSEQ:
- case OPSLASHEQ:
- case OPMODEQ:
- case OPLSHIFTEQ:
- case OPRSHIFTEQ:
- case OPBITANDEQ:
- case OPBITXOREQ:
- case OPBITOREQ:
-
- case OPCONV:
- case OPADDR:
- case OPWHATSIN:
-
- case OPCOMMA:
- case OPCOMMA_ARG:
- case OPQUEST:
- case OPCOLON:
- case OPDOT:
- case OPARROW:
- case OPIDENTITY:
- case OPCHARCAST:
- case OPABS:
- case OPDABS:
- break;
-
- default:
- badop("mkexpr", opcode);
- }
-
- e = (expptr) ALLOC(Exprblock);
- e->exprblock.tag = TEXPR;
- e->exprblock.opcode = opcode;
- e->exprblock.vtype = etype;
- e->exprblock.leftp = lp;
- e->exprblock.rightp = rp;
- if(ltag==TCONST && (rp==0 || rtag==TCONST) )
- e = fold(e);
- return(e);
-
- retleft:
- frexpr(rp);
- return(lp);
-
- retright:
- frexpr(lp);
- return(rp);
-
- error:
- frexpr(lp);
- if(rp && opcode!=OPCALL && opcode!=OPCCALL)
- frexpr(rp);
- return( errnode() );
- }
-
- #define ERR(s) { errs = s; goto error; }
-
- /* cktype -- Check and return the type of the expression */
-
- cktype(op, lt, rt)
- register int op, lt, rt;
- {
- char *errs;
-
- if(lt==TYERROR || rt==TYERROR)
- goto error1;
-
- if(lt==TYUNKNOWN)
- return(TYUNKNOWN);
- if(rt==TYUNKNOWN)
-
- /* If not unary operation, return UNKNOWN */
-
- if(!is_unary_op (op) && op != OPCALL && op != OPCCALL)
- return(TYUNKNOWN);
-
- switch(op)
- {
- case OPPLUS:
- case OPMINUS:
- case OPSTAR:
- case OPSLASH:
- case OPPOWER:
- case OPMOD:
- if( ISNUMERIC(lt) && ISNUMERIC(rt) )
- return( maxtype(lt, rt) );
- ERR("nonarithmetic operand of arithmetic operator")
-
- case OPNEG:
- case OPNEG1:
- if( ISNUMERIC(lt) )
- return(lt);
- ERR("nonarithmetic operand of negation")
-
- case OPNOT:
- if(lt == TYLOGICAL)
- return(TYLOGICAL);
- ERR("NOT of nonlogical")
-
- case OPAND:
- case OPOR:
- case OPEQV:
- case OPNEQV:
- if(lt==TYLOGICAL && rt==TYLOGICAL)
- return(TYLOGICAL);
- ERR("nonlogical operand of logical operator")
-
- case OPLT:
- case OPGT:
- case OPLE:
- case OPGE:
- case OPEQ:
- case OPNE:
- if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL)
- {
- if(lt != rt)
- ERR("illegal comparison")
- }
-
- else if( ISCOMPLEX(lt) || ISCOMPLEX(rt) )
- {
- if(op!=OPEQ && op!=OPNE)
- ERR("order comparison of complex data")
- }
-
- else if( ! ISNUMERIC(lt) || ! ISNUMERIC(rt) )
- ERR("comparison of nonarithmetic data")
- return(TYLOGICAL);
-
- case OPCONCAT:
- if(lt==TYCHAR && rt==TYCHAR)
- return(TYCHAR);
- ERR("concatenation of nonchar data")
-
- case OPCALL:
- case OPCCALL:
- case OPIDENTITY:
- return(lt);
-
- case OPADDR:
- case OPCHARCAST:
- return(TYADDR);
-
- case OPCONV:
- if(rt == 0)
- return(0);
- if(lt==TYCHAR && ISINT(rt) )
- return(TYCHAR);
- case OPASSIGN:
- case OPASSIGNI:
- case OPMINUSEQ:
- case OPPLUSEQ:
- case OPSTAREQ:
- case OPSLASHEQ:
- case OPMODEQ:
- case OPLSHIFTEQ:
- case OPRSHIFTEQ:
- case OPBITANDEQ:
- case OPBITXOREQ:
- case OPBITOREQ:
- if( ISINT(lt) && rt==TYCHAR)
- return(lt);
- if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL)
- if((op!=OPASSIGN && op != OPPLUSEQ && op != OPMINUSEQ)
- || (lt!=rt))
- {
- ERR("impossible conversion")
- }
- return(lt);
-
- case OPMIN:
- case OPMAX:
- case OPDMIN:
- case OPDMAX:
- case OPMIN2:
- case OPMAX2:
- case OPBITOR:
- case OPBITAND:
- case OPBITXOR:
- case OPBITNOT:
- case OPLSHIFT:
- case OPRSHIFT:
- case OPWHATSIN:
- case OPABS:
- case OPDABS:
- return(lt);
-
- case OPCOMMA:
- case OPCOMMA_ARG:
- case OPQUEST:
- case OPCOLON: /* Only checks the rightmost type because
- of C language definition (rightmost
- comma-expr is the value of the expr) */
- return(rt);
-
- case OPDOT:
- case OPARROW:
- return (lt);
- break;
- default:
- badop("cktype", op);
- }
- error:
- err(errs);
- error1:
- return(TYERROR);
- }
-
- /* fold -- simplifies constant expressions; it assumes that e -> leftp and
- e -> rightp are TCONST or NULL */
-
- LOCAL expptr
- fold(e)
- register expptr e;
- {
- Constp p;
- register expptr lp, rp;
- int etype, mtype, ltype, rtype, opcode;
- int i, bl, ll, lr;
- char *q, *s;
- struct Constblock lcon, rcon;
- long L;
- double d;
-
- opcode = e->exprblock.opcode;
- etype = e->exprblock.vtype;
-
- lp = e->exprblock.leftp;
- ltype = lp->headblock.vtype;
- rp = e->exprblock.rightp;
-
- if(rp == 0)
- switch(opcode)
- {
- case OPNOT:
- lp->constblock.Const.ci = ! lp->constblock.Const.ci;
- retlp:
- e->exprblock.leftp = 0;
- frexpr(e);
- return(lp);
-
- case OPBITNOT:
- lp->constblock.Const.ci = ~ lp->constblock.Const.ci;
- goto retlp;
-
- case OPNEG:
- case OPNEG1:
- consnegop((Constp)lp);
- goto retlp;
-
- case OPCONV:
- case OPADDR:
- return(e);
-
- case OPABS:
- case OPDABS:
- switch(ltype) {
- case TYSHORT:
- case TYLONG:
- if ((L = lp->constblock.Const.ci) < 0)
- lp->constblock.Const.ci = -L;
- goto retlp;
- case TYREAL:
- case TYDREAL:
- if (lp->constblock.vstg) {
- s = lp->constblock.Const.cds[0];
- if (*s == '-')
- lp->constblock.Const.cds[0] = s + 1;
- goto retlp;
- }
- if ((d = lp->constblock.Const.cd[0]) < 0.)
- lp->constblock.Const.cd[0] = -d;
- case TYCOMPLEX:
- case TYDCOMPLEX:
- return e; /* lazy way out */
- }
- default:
- badop("fold", opcode);
- }
-
- rtype = rp->headblock.vtype;
-
- p = ALLOC(Constblock);
- p->tag = TCONST;
- p->vtype = etype;
- p->vleng = e->exprblock.vleng;
-
- switch(opcode)
- {
- case OPCOMMA:
- case OPCOMMA_ARG:
- case OPQUEST:
- case OPCOLON:
- return(e);
-
- case OPAND:
- p->Const.ci = lp->constblock.Const.ci &&
- rp->constblock.Const.ci;
- break;
-
- case OPOR:
- p->Const.ci = lp->constblock.Const.ci ||
- rp->constblock.Const.ci;
- break;
-
- case OPEQV:
- p->Const.ci = lp->constblock.Const.ci ==
- rp->constblock.Const.ci;
- break;
-
- case OPNEQV:
- p->Const.ci = lp->constblock.Const.ci !=
- rp->constblock.Const.ci;
- break;
-
- case OPBITAND:
- p->Const.ci = lp->constblock.Const.ci &
- rp->constblock.Const.ci;
- break;
-
- case OPBITOR:
- p->Const.ci = lp->constblock.Const.ci |
- rp->constblock.Const.ci;
- break;
-
- case OPBITXOR:
- p->Const.ci = lp->constblock.Const.ci ^
- rp->constblock.Const.ci;
- break;
-
- case OPLSHIFT:
- p->Const.ci = lp->constblock.Const.ci <<
- rp->constblock.Const.ci;
- break;
-
- case OPRSHIFT:
- p->Const.ci = lp->constblock.Const.ci >>
- rp->constblock.Const.ci;
- break;
-
- case OPCONCAT:
- ll = lp->constblock.vleng->constblock.Const.ci;
- lr = rp->constblock.vleng->constblock.Const.ci;
- bl = lp->constblock.Const.ccp1.blanks;
- p->Const.ccp = q = (char *) ckalloc(ll+lr+bl);
- p->Const.ccp1.blanks = rp->constblock.Const.ccp1.blanks;
- p->vleng = ICON(ll+lr+bl);
- s = lp->constblock.Const.ccp;
- for(i = 0 ; i < ll ; ++i)
- *q++ = *s++;
- for(i = 0 ; i < bl ; i++)
- *q++ = ' ';
- s = rp->constblock.Const.ccp;
- for(i = 0; i < lr; ++i)
- *q++ = *s++;
- break;
-
-
- case OPPOWER:
- if( ! ISINT(rtype) )
- return(e);
- conspower(p, (Constp)lp, rp->constblock.Const.ci);
- break;
-
-
- default:
- if(ltype == TYCHAR)
- {
- lcon.Const.ci = cmpstr(lp->constblock.Const.ccp,
- rp->constblock.Const.ccp,
- lp->constblock.vleng->constblock.Const.ci,
- rp->constblock.vleng->constblock.Const.ci);
- rcon.Const.ci = 0;
- mtype = tyint;
- }
- else {
- mtype = maxtype(ltype, rtype);
- consconv(mtype, &lcon, &lp->constblock);
- consconv(mtype, &rcon, &rp->constblock);
- }
- consbinop(opcode, mtype, p, &lcon, &rcon);
- break;
- }
-
- frexpr(e);
- return( (expptr) p );
- }
-
-
-
- /* assign constant l = r , doing coercion */
-
- consconv(lt, lc, rc)
- int lt;
- register Constp lc, rc;
- {
- int rt = rc->vtype;
- register union Constant *lv = &lc->Const, *rv = &rc->Const;
-
- lc->vtype = lt;
- if (ONEOF(lt, MSKREAL|MSKCOMPLEX) && ONEOF(rt, MSKREAL|MSKCOMPLEX)) {
- memcpy((char *)lv, (char *)rv, sizeof(union Constant));
- lc->vstg = rc->vstg;
- if (ISCOMPLEX(lt) && ISREAL(rt)) {
- if (rc->vstg)
- lv->cds[1] = cds("0",CNULL);
- else
- lv->cd[1] = 0.;
- }
- return;
- }
- lc->vstg = 0;
-
- switch(lt)
- {
-
- /* Casting to character means just copying the first sizeof (character)
- bytes into a new 1 character string. This is weird. */
-
- case TYCHAR:
- *(lv->ccp = (char *) ckalloc(1)) = rv->ci;
- lv->ccp1.blanks = 0;
- break;
-
- case TYSHORT:
- case TYLONG:
- if(rt == TYCHAR)
- lv->ci = rv->ccp[0];
- else if( ISINT(rt) )
- lv->ci = rv->ci;
- else lv->ci = rc->vstg ? atof(rv->cds[0]) : rv->cd[0];
-
- break;
-
- case TYCOMPLEX:
- case TYDCOMPLEX:
- lv->cd[1] = 0.;
- lv->cd[0] = rv->ci;
- break;
-
- case TYREAL:
- case TYDREAL:
- lv->cd[0] = rv->ci;
- break;
-
- case TYLOGICAL:
- lv->ci = rv->ci;
- break;
- }
- }
-
-
-
- /* Negate constant value -- changes the input node's value */
-
- consnegop(p)
- register Constp p;
- {
- register char *s;
-
- if (p->vstg) {
- if (ISCOMPLEX(p->vtype)) {
- s = p->Const.cds[1];
- p->Const.cds[1] = *s == '-' ? s+1
- : *s == '0' ? s : s-1;
- }
- s = p->Const.cds[0];
- p->Const.cds[0] = *s == '-' ? s+1
- : *s == '0' ? s : s-1;
- return;
- }
- switch(p->vtype)
- {
- case TYSHORT:
- case TYLONG:
- p->Const.ci = - p->Const.ci;
- break;
-
- case TYCOMPLEX:
- case TYDCOMPLEX:
- p->Const.cd[1] = - p->Const.cd[1];
- /* fall through and do the real parts */
- case TYREAL:
- case TYDREAL:
- p->Const.cd[0] = - p->Const.cd[0];
- break;
- default:
- badtype("consnegop", p->vtype);
- }
- }
-
-
-
- /* conspower -- Expand out an exponentiation */
-
- LOCAL void
- conspower(p, ap, n)
- Constp p, ap;
- ftnint n;
- {
- register union Constant *powp = &p->Const;
- register int type;
- struct Constblock x, x0;
-
- if (n == 1) {
- memcpy((char *)powp, (char *)&ap->Const, sizeof(ap->Const));
- return;
- }
-
- switch(type = ap->vtype) /* pow = 1 */
- {
- case TYSHORT:
- case TYLONG:
- powp->ci = 1;
- break;
- case TYCOMPLEX:
- case TYDCOMPLEX:
- powp->cd[1] = 0;
- case TYREAL:
- case TYDREAL:
- powp->cd[0] = 1;
- break;
- default:
- badtype("conspower", type);
- }
-
- if(n == 0)
- return;
- switch(type) /* x0 = ap */
- {
- case TYSHORT:
- case TYLONG:
- x0.Const.ci = ap->Const.ci;
- break;
- case TYCOMPLEX:
- case TYDCOMPLEX:
- x0.Const.cd[1] =
- ap->vstg ? atof(ap->Const.cds[1]) : ap->Const.cd[1];
- case TYREAL:
- case TYDREAL:
- x0.Const.cd[0] =
- ap->vstg ? atof(ap->Const.cds[0]) : ap->Const.cd[0];
- break;
- }
- x0.vtype = type;
- x0.vstg = 0;
- if(n < 0)
- {
- if( ISINT(type) )
- {
- err("integer ** negative number");
- return;
- }
- else if (!x0.Const.cd[0]
- && (!ISCOMPLEX(type) || !x0.Const.cd[1])) {
- err("0.0 ** negative number");
- return;
- }
- n = -n;
- consbinop(OPSLASH, type, &x, p, &x0);
- }
- else
- consbinop(OPSTAR, type, &x, p, &x0);
-
- for( ; ; )
- {
- if(n & 01)
- consbinop(OPSTAR, type, p, p, &x);
- if(n >>= 1)
- consbinop(OPSTAR, type, &x, &x, &x);
- else
- break;
- }
- }
-
-
-
- /* do constant operation cp = a op b -- assumes that ap and bp have data
- matching the input type */
-
-
- LOCAL void
- consbinop(opcode, type, cpp, app, bpp)
- int opcode, type;
- Constp cpp, app, bpp;
- {
- register union Constant *ap = &app->Const,
- *bp = &bpp->Const,
- *cp = &cpp->Const;
- int k;
- double ad[2], bd[2], temp;
-
- cpp->vstg = 0;
-
- if (ONEOF(type, MSKREAL|MSKCOMPLEX)) {
- ad[0] = app->vstg ? atof(ap->cds[0]) : ap->cd[0];
- bd[0] = bpp->vstg ? atof(bp->cds[0]) : bp->cd[0];
- if (ISCOMPLEX(type)) {
- ad[1] = app->vstg ? atof(ap->cds[1]) : ap->cd[1];
- bd[1] = bpp->vstg ? atof(bp->cds[1]) : bp->cd[1];
- }
- }
- switch(opcode)
- {
- case OPPLUS:
- switch(type)
- {
- case TYSHORT:
- case TYLONG:
- cp->ci = ap->ci + bp->ci;
- break;
- case TYCOMPLEX:
- case TYDCOMPLEX:
- cp->cd[1] = ad[1] + bd[1];
- case TYREAL:
- case TYDREAL:
- cp->cd[0] = ad[0] + bd[0];
- break;
- }
- break;
-
- case OPMINUS:
- switch(type)
- {
- case TYSHORT:
- case TYLONG:
- cp->ci = ap->ci - bp->ci;
- break;
- case TYCOMPLEX:
- case TYDCOMPLEX:
- cp->cd[1] = ad[1] - bd[1];
- case TYREAL:
- case TYDREAL:
- cp->cd[0] = ad[0] - bd[0];
- break;
- }
- break;
-
- case OPSTAR:
- switch(type)
- {
- case TYSHORT:
- case TYLONG:
- cp->ci = ap->ci * bp->ci;
- break;
- case TYREAL:
- case TYDREAL:
- cp->cd[0] = ad[0] * bd[0];
- break;
- case TYCOMPLEX:
- case TYDCOMPLEX:
- temp = ad[0] * bd[0] - ad[1] * bd[1] ;
- cp->cd[1] = ad[0] * bd[1] + ad[1] * bd[0] ;
- cp->cd[0] = temp;
- break;
- }
- break;
- case OPSLASH:
- switch(type)
- {
- case TYSHORT:
- case TYLONG:
- cp->ci = ap->ci / bp->ci;
- break;
- case TYREAL:
- case TYDREAL:
- cp->cd[0] = ad[0] / bd[0];
- break;
- case TYCOMPLEX:
- case TYDCOMPLEX:
- zdiv((dcomplex*)cp, (dcomplex*)ad, (dcomplex*)bd);
- break;
- }
- break;
-
- case OPMOD:
- if( ISINT(type) )
- {
- cp->ci = ap->ci % bp->ci;
- break;
- }
- else
- Fatal("inline mod of noninteger");
-
- case OPMIN2:
- case OPDMIN:
- switch(type)
- {
- case TYSHORT:
- case TYLONG:
- cp->ci = ap->ci <= bp->ci ? ap->ci : bp->ci;
- break;
- case TYREAL:
- case TYDREAL:
- cp->cd[0] = ad[0] <= bd[0] ? ad[0] : bd[0];
- break;
- default:
- Fatal("inline min of exected type");
- }
- break;
-
- case OPMAX2:
- case OPDMAX:
- switch(type)
- {
- case TYSHORT:
- case TYLONG:
- cp->ci = ap->ci >= bp->ci ? ap->ci : bp->ci;
- break;
- case TYREAL:
- case TYDREAL:
- cp->cd[0] = ad[0] >= bd[0] ? ad[0] : bd[0];
- break;
- default:
- Fatal("inline max of exected type");
- }
- break;
-
- default: /* relational ops */
- switch(type)
- {
- case TYSHORT:
- case TYLONG:
- if(ap->ci < bp->ci)
- k = -1;
- else if(ap->ci == bp->ci)
- k = 0;
- else k = 1;
- break;
- case TYREAL:
- case TYDREAL:
- if(ad[0] < bd[0])
- k = -1;
- else if(ad[0] == bd[0])
- k = 0;
- else k = 1;
- break;
- case TYCOMPLEX:
- case TYDCOMPLEX:
- if(ad[0] == bd[0] &&
- ad[1] == bd[1] )
- k = 0;
- else k = 1;
- break;
- }
-
- switch(opcode)
- {
- case OPEQ:
- cp->ci = (k == 0);
- break;
- case OPNE:
- cp->ci = (k != 0);
- break;
- case OPGT:
- cp->ci = (k == 1);
- break;
- case OPLT:
- cp->ci = (k == -1);
- break;
- case OPGE:
- cp->ci = (k >= 0);
- break;
- case OPLE:
- cp->ci = (k <= 0);
- break;
- }
- break;
- }
- }
-
-
-
- /* conssgn - returns the sign of a Fortran constant */
-
- conssgn(p)
- register expptr p;
- {
- register char *s;
-
- if( ! ISCONST(p) )
- Fatal( "sgn(nonconstant)" );
-
- switch(p->headblock.vtype)
- {
- case TYSHORT:
- case TYLONG:
- if(p->constblock.Const.ci > 0) return(1);
- if(p->constblock.Const.ci < 0) return(-1);
- return(0);
-
- case TYREAL:
- case TYDREAL:
- if (p->constblock.vstg) {
- s = p->constblock.Const.cds[0];
- if (*s == '-')
- return -1;
- if (*s == '0')
- return 0;
- return 1;
- }
- if(p->constblock.Const.cd[0] > 0) return(1);
- if(p->constblock.Const.cd[0] < 0) return(-1);
- return(0);
-
-
- /* The sign of a complex number is 0 iff the number is 0 + 0i, else it's 1 */
-
- case TYCOMPLEX:
- case TYDCOMPLEX:
- if (p->constblock.vstg)
- return *p->constblock.Const.cds[0] != '0'
- && *p->constblock.Const.cds[1] != '0';
- return(p->constblock.Const.cd[0]!=0 || p->constblock.Const.cd[1]!=0);
-
- default:
- badtype( "conssgn", p->constblock.vtype);
- }
- /* NOT REACHED */ return 0;
- }
-
- char *powint[ ] = {
- "pow_ii", "pow_ri", "pow_di", "pow_ci", "pow_zi" };
-
- LOCAL expptr mkpower(p)
- register expptr p;
- {
- register expptr q, lp, rp;
- int ltype, rtype, mtype, tyi;
-
- lp = p->exprblock.leftp;
- rp = p->exprblock.rightp;
- ltype = lp->headblock.vtype;
- rtype = rp->headblock.vtype;
-
- if(ISICON(rp))
- {
- if(rp->constblock.Const.ci == 0)
- {
- frexpr(p);
- if( ISINT(ltype) )
- return( ICON(1) );
- else if (ISREAL (ltype))
- return mkconv (ltype, ICON (1));
- else
- return( (expptr) putconst((Constp)
- mkconv(ltype, ICON(1))) );
- }
- if(rp->constblock.Const.ci < 0)
- {
- if( ISINT(ltype) )
- {
- frexpr(p);
- err("integer**negative");
- return( errnode() );
- }
- rp->constblock.Const.ci = - rp->constblock.Const.ci;
- p->exprblock.leftp = lp
- = fixexpr((Exprp)mkexpr(OPSLASH, ICON(1), lp));
- }
- if(rp->constblock.Const.ci == 1)
- {
- frexpr(rp);
- free( (charptr) p );
- return(lp);
- }
-
- if( ONEOF(ltype, MSKINT|MSKREAL) && !doin_setbound) {
- p->exprblock.vtype = ltype;
- return(p);
- }
- }
- if( ISINT(rtype) )
- {
- if(ltype==TYSHORT && rtype==TYSHORT && (!ISCONST(lp) || tyint==TYSHORT) )
- q = call2(TYSHORT, "pow_hh", lp, rp);
- else {
- if(ltype == TYSHORT)
- {
- ltype = TYLONG;
- lp = mkconv(TYLONG,lp);
- }
- rp = mkconv(TYLONG,rp);
- if (ISCONST(rp)) {
- tyi = tyint;
- tyint = TYLONG;
- rp = (expptr)putconst((Constp)rp);
- tyint = tyi;
- }
- q = call2(ltype, powint[ltype-TYLONG], lp, rp);
- }
- }
- else if( ISREAL( (mtype = maxtype(ltype,rtype)) )) {
- extern int callk_kludge;
- callk_kludge = TYDREAL;
- q = call2(mtype, "pow_dd", mkconv(TYDREAL,lp), mkconv(TYDREAL,rp));
- callk_kludge = 0;
- }
- else {
- q = call2(TYDCOMPLEX, "pow_zz",
- mkconv(TYDCOMPLEX,lp), mkconv(TYDCOMPLEX,rp));
- if(mtype == TYCOMPLEX)
- q = mkconv(TYCOMPLEX, q);
- }
- free( (charptr) p );
- return(q);
- }
-
-
- /* Complex Division. Same code as in Runtime Library
- */
-
-
- LOCAL void
- zdiv(c, a, b)
- register dcomplex *a, *b, *c;
- {
- double ratio, den;
- double abr, abi;
-
- if( (abr = b->dreal) < 0.)
- abr = - abr;
- if( (abi = b->dimag) < 0.)
- abi = - abi;
- if( abr <= abi )
- {
- if(abi == 0)
- Fatal("complex division by zero");
- ratio = b->dreal / b->dimag ;
- den = b->dimag * (1 + ratio*ratio);
- c->dreal = (a->dreal*ratio + a->dimag) / den;
- c->dimag = (a->dimag*ratio - a->dreal) / den;
- }
-
- else
- {
- ratio = b->dimag / b->dreal ;
- den = b->dreal * (1 + ratio*ratio);
- c->dreal = (a->dreal + a->dimag*ratio) / den;
- c->dimag = (a->dimag - a->dreal*ratio) / den;
- }
- }
-