#include #include "defs" /* basic simplifying procedure */ ptr simple(t,e) int t; /* take on the values LVAL, RVAL, and SUBVAL */ register ptr e; /* points to an expression */ { int tag, subtype; ptr lp, rp; int ltag; int lsubt; ptr p, e1; ptr exio(), exioop(), dblop(), setfield(), gentemp(); int a,b,c; top: if(e == 0) return(0); tag = e->tag; subtype = e->subtype; if(lp = e->leftp) { ltag = lp->tag; lsubt = lp->subtype; } rp = e->rightp; TEST fprintf(diagfile, "simple(%d; tag %d,%d)\n", t,tag,subtype); switch(tag){ case TNOTOP: switch(ltag) { case TNOTOP: /* not not = yes */ frexpblock(e); e = lp->leftp; frexpblock(lp); goto top; case TLOGOP: /* de Morgan's Law */ lp->subtype = (OPOR+OPAND) - lp->subtype; lp->leftp = mknode(TNOTOP,OPNOT,lp->leftp, PNULL); lp->rightp=mknode(TNOTOP,OPNOT,lp->rightp, PNULL); frexpblock(e); e = lp; goto top; case TRELOP: /* reverse the condition */ lp->subtype = (OPEQ+OPNE) - lp->subtype; frexpblock(e); e = lp; goto top; case TCALL: case TASGNOP: e->leftp = simple(RVAL,lp); case TNAME: case TFTNBLOCK: lp = simple(RVAL,lp); case TTEMP: if(t == LVAL) e = simple(LVAL, mknode(TASGNOP,0, gentemp(e->leftp), e)); break; case TCONST: if(equals(lp->leftp, ".false.")) e->leftp = copys(".true."); else if(equals(lp->leftp, ".true.")) e->leftp = copys(".false."); else goto typerr; e->tag = TCONST; e->subtype = 0; cfree(lp->leftp); frexpblock(lp); break; default: goto typerr; } break; case TLOGOP: switch(subtype) { case OPOR: case OPAND: goto binop; case OP2OR: case OP2AND: lp = e->leftp = simple(RVAL, lp); if(lp->tag != TTEMP) lp = simple(RVAL, mknode(TASGNOP,0, gent(TYLOG,0),lp)); return( simple(LVAL, mknode(TASGNOP,subtype,lp,rp)) ); default: fatal("impossible logical operator"); } case TNEGOP: lp = e->leftp = simple(RVAL,lp); ltag = lp->tag; lsubt = lp->subtype; if(ltag==TNEGOP) { frexpblock(e); e = lp->leftp; frexpblock(lp); goto top; } else goto lvcheck; case TAROP: case TRELOP: binop: e->leftp = simple(RVAL,lp); lp = e->leftp; ltag = lp->tag; lsubt = lp->subtype; e->rightp= simple(RVAL,rp); rp = e->rightp; if(tag==TAROP && isicon(rp,&b) ) { /* simplify a*1, a/1 , a+0, a-0 */ if( ((subtype==OPSTAR||subtype==OPSLASH) && b==1) || ((subtype==OPPLUS||subtype==OPMINUS) && b==0) ) { frexpr(rp); mvexpr(lp,e); goto top; } if(isicon(lp, &a)) /* try folding const op const */ { e1 = fold(e); if(e1!=e || e1->tag!=TAROP) { e = e1; goto top; } } if(ltag==TAROP && lp->needpar==0 && isicon(lp->rightp,&a) ) { /* look for cases of (e op const ) op' const */ if( (subtype==OPPLUS||subtype==OPMINUS) && (lsubt==OPPLUS||lsubt==OPMINUS) ) { /* (e +- const) +- const */ c = (subtype==OPPLUS ? 1 : -1) * b + (lsubt==OPPLUS? 1 : -1) * a; if(c > 0) subtype = OPPLUS; else { subtype = OPMINUS; c = -c; } fixexpr: frexpr(rp); frexpr(lp->rightp); frexpblock(e); e = lp; e->subtype = subtype; e->rightp = mkint(c); goto top; } else if(lsubt==OPSTAR && ( (subtype==OPSTAR) || (subtype==OPSLASH && a%b==0)) ) { /* (e * const ) (* or /) const */ c = (subtype==OPSTAR ? a*b : a/b ); subtype = OPSTAR; goto fixexpr; } } if(ltag==TAROP && (lsubt==OPPLUS || lsubt==OPMINUS) && subtype==OPSLASH && divides(lp,conval(rp)) ) { e->leftp = mknode(TAROP,OPSLASH,lp->leftp, cpexpr(rp)); e->rightp = mknode(TAROP,OPSLASH,lp->rightp, rp); e->subtype = lsubt; goto top; } } else if( tag==TRELOP && isicon(lp,&a) && isicon(rp,&b) ) { e1 = fold(e); if(e1!=e || e1->tag!=TRELOP) { e = e1; goto top; } } lvcheck: if(t == LVAL) e = simple(LVAL, mknode(TASGNOP,0, gentemp(e),e)); else if(t == SUBVAL) { /* test for legal Fortran c*v +-c form */ if(tag==TAROP && (subtype==OPPLUS || subtype==OPMINUS)) if(rp->tag==TCONST && rp->vtype==TYINT) { if(!cvform(lp)) e->leftp = simple(SUBVAL, lp); } else goto makesub; else if( !cvform(e) ) goto makesub; } break; case TCALL: if( lp->tag!=TFTNBLOCK && ioop(lp->sthead->namep) ) { e = exioop(e, YES); exlab(0); break; } e->rightp = simple(RVAL, rp); if(t == SUBVAL) goto makesub; if(t == LVAL) e = simple(RVAL, mknode(TASGNOP,0, gentemp(e),e)); break; case TNAME: if(e->voffset) fixsubs(e); if(e->vsubs) e->vsubs = simple(SUBVAL, e->vsubs); if(t==SUBVAL && !vform(e)) goto makesub; case TTEMP: case TFTNBLOCK: case TCONST: if(t==SUBVAL && e->vtype!=TYINT) goto makesub; break; case TASGNOP: lp = e->leftp = simple(LVAL,lp); if(subtype==OP2OR || subtype==OP2AND) e = dblop(e); else { rp = e->rightp = simple(RVAL,rp); if(e->vtype == TYCHAR) excall(mkcall(mkftnblock(TYSUBR,"ef1asc"), arg4(cpexpr(lp),rp))); else if(e->vtype == TYSTRUCT) { if(lp->vtypep->strsize != rp->vtypep->strsize) fatal("simple: attempt to assign incompatible structures"); e1 = mkchain(cpexpr(lp),mkchain(rp, mkchain(mkint(lp->vtypep->strsize),CHNULL))); excall(mkcall(mkftnblock(TYSUBR,"ef1ass"), mknode(TLIST, 0, e1, PNULL) )); } else if(lp->vtype == TYFIELD) lp = setfield(e); else { if(subtype != OPASGN) /* but is one of += etc */ { rp = e->rightp = simple(RVAL, mknode( (subtype<=OPPOWER?TAROP:TLOGOP),subtype, cpexpr(e->leftp),e->rightp)); e->subtype = OPASGN; } exlab(0); prexpr(e); frexpr(rp); } frexpblock(e); e = lp; if(t == SUBVAL) goto top; } break; case TLIST: for(p=lp ; p ; p = p->nextp) p->datap = simple(t, p->datap); break; case TIOSTAT: e = exio(e, 1); break; default: break; } return(e); typerr: exprerr("type match error", CNULL); return(e); makesub: if(t==SUBVAL && e->vtype!=TYINT) warn1("Line %d. Non-integer subscript", yylineno); return( simple(RVAL, mknode(TASGNOP,0,gent(TYINT,PNULL),e)) ); } ptr fold(e) register ptr e; { int a, b, c; register ptr lp, rp; lp = e->leftp; rp = e->rightp; if(lp->tag!=TCONST && lp->tag!=TNEGOP) return(e); if(rp->tag!=TCONST && rp->tag!=TNEGOP) return(e); switch(e->tag) { case TAROP: if( !isicon(lp,&a) || !isicon(rp,&b) ) return(e); switch(e->subtype) { case OPPLUS: c = a + b;break; case OPMINUS: c = a - b; break; case OPSTAR: c = a * b; break; case OPSLASH: if(a%b!=0 && (a<0 || b<0) ) return(e); c = a / b; break; case OPPOWER: return(e); default: fatal("fold: illegal binary operator"); } frexpr(e); if(c >= 0) return( mkint(c) ); else return(mknode(TNEGOP,OPMINUS, mkint(-c), PNULL) ); case TRELOP: if( !isicon(lp,&a) || !isicon(rp,&b) ) return(e); frexpr(e); switch(e->subtype) { case OPEQ: c = a == b; break; case OPLT: c = a < b ; break; case OPGT: c = a > b; break; case OPLE: c = a <= b; break; case OPGE: c = a >= b; break; case OPNE: c = a != b; break; default: fatal("fold: invalid relational operator"); } return( mkconst(TYLOG, (c ? ".true." : ".false.")) ); case TLOGOP: if(lp->vtype!=TYLOG || rp->vtype!=TYLOG) return(e); a = equals(lp->leftp, ".true."); b = equals(rp->leftp, ".true."); frexpr(e); switch(e->subtype) { case OPAND: case OP2AND: c = a & b; break; case OPOR: case OP2OR: c = a | b; break; default: fatal("fold: invalid logical operator"); } return( mkconst(TYLOG, (c? ".true." : ".false")) ); default: return(e); } } #define TO + 100* ptr coerce(t,e) /* coerce expression e to type t */ int t; register ptr e; { register int et; int econst; char buff[100]; char *s, *s1; ptr conrep(), xfixf(); if(e->tag == TNEGOP) { e->leftp = coerce(t, e->leftp); goto settype; } et = e->vtype; econst = (e->tag == TCONST); TEST fprintf(diagfile, "coerce type %d to type %d\n", et, t); if(t == et) return(e); switch( et TO t ) { case TYCOMPLEX TO TYINT: case TYLREAL TO TYINT: e = coerce(TYREAL,e); case TYREAL TO TYINT: if(econst) e = xfixf(e); if(e->vtype != TYINT) e = mkcall(builtin(TYINT,"ifix"), arg1(e)); break; case TYINT TO TYREAL: if(econst) { e->leftp = conrep(e->leftp, "."); goto settype; } e = mkcall(builtin(TYREAL,"float"), arg1(e)); break; case TYLREAL TO TYREAL: if(econst) { for(s=e->leftp ; *s && *s!='d';++s) ; *s = 'e'; goto settype; } e = mkcall(builtin(TYREAL,"sngl"), arg1(e)); break; case TYCOMPLEX TO TYREAL: if(econst) { s1 = (char *)(e->leftp) + 1; s = buff; while(*s1!=',' && *s1!='\0') *s1++ = *s++; *s = '\0'; cfree(e->leftp); e->leftp = copys(buff); goto settype; } else e = mkcall(mkftnblock(TYREAL,"real"), arg1(e)); break; case TYINT TO TYLREAL: if(econst) { e->leftp = conrep(e->leftp,"d0"); goto settype; } case TYCOMPLEX TO TYLREAL: e = coerce(TYREAL,e); case TYREAL TO TYLREAL: if(econst) { for(s=e->leftp ; *s && *s!='e'; ++s) ; if(*s == 'e') *s = 'd'; else e->leftp = conrep(e->leftp,"d0"); goto settype; } e = mkcall(builtin(TYLREAL,"dble"), arg1(e)); break; case TYINT TO TYCOMPLEX: case TYLREAL TO TYCOMPLEX: e = coerce(TYREAL, e); case TYREAL TO TYCOMPLEX: if(e->tag == TCONST) { sprintf(buff, "(%s,0.)", e->leftp); cfree(e->leftp); e->leftp = copys(buff); goto settype; } else e = mkcall(builtin(TYCOMPLEX,"cmplx"), arg2(e, mkconst(TYREAL,"0."))); break; default: goto mismatch; } return(e); mismatch: exprerr("impossible conversion", ""); frexpr(e); return( errnode() ); settype: e->vtype = t; return(e); } /* check whether expression is in form c, v, or v*c */ cvform(p) register ptr p; { switch(p->tag) { case TCONST: return(p->vtype == TYINT); case TNAME: return(vform(p)); case TAROP: if(p->subtype==OPSTAR && p->rightp->tag==TCONST && p->rightp->vtype==TYINT && vform(p->leftp)) return(1); default: return(0); } } /* is p a simple integer variable */ vform(p) register ptr p; { return( p->tag==TNAME && p->vtype==TYINT && p->vdim==0 && p->voffset==0 && p->vsubs==0) ; } ptr dblop(p) ptr p; { ptr q; bgnexec(); if(p->subtype == OP2OR) q = mknode(TNOTOP,OPNOT, cpexpr(p->leftp), PNULL); else q = cpexpr(p->leftp); pushctl(STIF, q); bgnexec(); exasgn(cpexpr(p->leftp), OPASGN, p->rightp); ifthen(); popctl(); addexec(); return(p->leftp); } divides(a,b) ptr a; int b; { if(a->vtype!=TYINT) return(0); switch(a->tag) { case TNEGOP: return( divides(a->leftp,b) ); case TCONST: return( conval(a) % b == 0); case TAROP: switch(a->subtype) { case OPPLUS: case OPMINUS: return(divides(a->leftp,b)&& divides(a->rightp,b) ); case OPSTAR: return(divides(a->rightp,b)); default: return(0); } default: return(0); } /* NOTREACHED */ } /* truncate floating point constant to integer */ #define MAXD 100 ptr xfixf(e) struct exprblock *e; { char digit[MAXD+1]; /* buffer into which digits are placed */ char *first; /* points to first nonzero digit */ register char *end; /* points at position past last digit */ register char *dot; /* decimal point is immediately to left of this digit */ register char *s; int expon; dot = NULL; end = digit; expon = 0; for(s = e->leftp ; *s; ++s) if( isdigit(*s) ) { if(end-digit > MAXD) return(e); *end++ = *s; } else if(*s == '.') dot = end; else if(*s=='d' || *s=='e') { expon = convci(s+1); break; } else fatal1("impossible character %d in floating constant", *s); if(dot == NULL) dot = end; dot += expon; if(dot-digit > MAXD) return(e); for(first = digit; firstleftp); e->leftp = copys(first); e->vtype = TYINT; return(e); }