/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg * * Permission is granted to anyone to use this software for any purpose * on any computer system, and to redistribute it freely, with the * following restrictions: * 1) No charge may be made other than reasonable charges for reproduction. * 2) Modified versions must be clearly marked as such. * 3) The authors are not responsible for any harmful consequences * of using this software, even if they result from defects in it. * * p2.c * * Expression tree routines. * * Constant folding, typing of nodes, simple transformations. */ #include #include "param.h" #include "tok.h" #include "nodes.h" #include "cookie.h" #if MMCC overlay "pass2" #endif extern int xflags[]; #define debug xflags['t'-'a'] extern nmerrors; NODEP bas_type(); do_expr(np, cookie) NODE *np; { if (np == NULL) return; /* include if want only one error at a time if (nmerrors) { freenode(np); return; } */ p2_expr(&np); genx(np, cookie); } p2_expr(npp) NODEP *npp; { NODEP np = *npp; if (np == NULL) return; if (debug > 1) { printf("P2 enter"); printnode(np); } confold(npp,0); np = *npp; form_types(np); if (debug) { printf("p2_expr"); printnode(np); } return; } form_types(np) NODEP np; { if (np == NULL) return; switch (np->e_type) { case E_SPEC: switch (np->e_token) { /* special cases */ case '.': case ARROW: form_types(np->n_left); sel_type(np); return; case '(': if (np->n_right) { form_types(np->n_right); /* args */ np->e_type = E_BIN; } else np->e_type = E_UNARY; fun_type(np); return; } /* fall through */ case E_BIN: form_types(np->n_left); form_types(np->n_right); b_types(np); break; case E_UNARY: form_types(np->n_left); u_types(np); break; case E_LEAF: l_types(np); break; } } /* (fun) (args) */ fun_type(np) NODEP np; { NODEP lp, typ; NODEP allsyms(), new_fun(); lp = np->n_left; if (lp->e_token == ID) { /* may be new ID */ typ = allsyms(lp); if (typ == NULL) typ = new_fun(lp); typ = typ->n_tptr; lp->n_tptr = typ; lp->n_flags |= N_COPYT; } else { form_types(lp); typ = lp->n_tptr; } if (typ->t_token != '(') { /* fun ret ? */ error("call non-fun"); goto bad; } typ = typ->n_tptr; goto good; bad: typ = bas_type(K_INT); good: np->n_tptr = typ; np->n_flags |= N_COPYT; } /* (struct|union) (. or ->) ID */ sel_type(xp) NODEP xp; { NODEP np, sup; int tok; NODEP rv; NODEP llook(); np = xp->n_right; sup = xp->n_left->n_tptr; tok = xp->e_token; /* already checked that np->e_token == ID */ if (tok == ARROW) { if (sup->t_token != STAR) { error("(non pointer)->"); goto bad; } sup = sup->n_tptr; } if (sup->t_token != K_STRUCT && sup->t_token != K_UNION) { error("select non-struct"); goto bad; } rv = llook(sup->n_right, np); if (rv == NULL) { error("? member ID"); goto bad; } xp->e_offs = rv->e_offs; if (rv->e_fldw) { xp->e_fldw = rv->e_fldw; xp->e_fldo = rv->e_fldo; } rv = rv->n_tptr; goto good; bad: rv = bas_type(K_INT); good: xp->n_tptr = rv; xp->n_flags |= N_COPYT; /* change to UNARY op */ xp->e_type = E_UNARY; freenode(np); xp->n_right = NULL; /* change ARY OF to PTR TO */ if (rv->t_token == '[') see_array(xp); } l_types(np) register NODE *np; { NODEP allsyms(); register NODE *tp; switch (np->e_token) { case ID: /* already did see_id */ if (np->n_tptr->t_token == '[') /* change to &ID */ see_array(np); return; case ICON: tp = bas_type(icon_ty(np)); break; case FCON: tp = bas_type(K_DOUBLE); break; case SCON: tp = bas_type(SCON); break; default: errors("Weird leaf",np->n_name); bad: tp = bas_type(K_INT); } np->n_tptr = tp; np->n_flags |= N_COPYT; } u_types(np) NODEP np; { NODEP tp; NODEP lp = np->n_left; NODEP normalty(); tp = lp->n_tptr; /* default */ switch (np->e_token) { case DOUBLE '+': case DOUBLE '-': case POSTINC: case POSTDEC: mustlval(lp); mustty(lp, R_SCALAR); if (tp->t_token == STAR) np->e_offs = tp->n_tptr->t_size; else np->e_offs = 1; break; case STAR: if (mustty(lp, R_POINTER)) goto bad; tp = tp->n_tptr; np->n_tptr = tp; np->n_flags |= N_COPYT; /* Ary of to Ptr to */ if (tp->t_token == '[') see_array(np); return; case UNARY '&': mustlval(lp); tp = allocnode(); tp->n_tptr = lp->n_tptr; tp->n_flags |= N_COPYT; tp->t_token = STAR; sprintf(tp->n_name, "Ptr to"); tp->t_size = SIZE_P; np->n_tptr = tp; return; /* no COPYT */ case UNARY '-': mustty(lp, R_ARITH); tp = normalty(lp, NULL); break; case TCONV: mustty(lp, R_SCALAR); if (np->n_tptr->t_token != K_VOID) mustty(np, R_SCALAR); return; /* type already specified */ case '!': mustty(lp, R_SCALAR); tp = bas_type(K_INT); break; case '~': mustty(lp, R_INTEGRAL); tp = normalty(lp, NULL); break; default: error("bad unary type"); bad: tp = bas_type(K_INT); } np->n_tptr = tp; np->n_flags |= N_COPYT; } b_types(np) NODEP np; { NODEP tp; NODEP lp, rp; NODEP normalty(), addty(), colonty(); int op; op = np->e_token; if (isassign(op)) { mustlval(np->n_left); op -= (ASSIGN 0); } lp = np->n_left; rp = np->n_right; tp = bas_type(K_INT); switch (op) { case '*': case '/': mustty(lp, R_ARITH); mustty(rp, R_ARITH); tp = normalty(lp,rp); break; case '%': case '&': case '|': case '^': mustty(lp, R_INTEGRAL); mustty(rp, R_INTEGRAL); tp = normalty(lp,rp); break; case '+': case '-': mustty(lp, R_SCALAR); mustty(rp, R_SCALAR); tp = addty(np); break; case DOUBLE '<': case DOUBLE '>': mustty(lp, R_INTEGRAL); mustty(rp, R_INTEGRAL); tp = normalty(lp, NULL); break; case '<': case '>': case LTEQ: case GTEQ: case DOUBLE '=': case NOTEQ: mustty(lp, R_SCALAR); mustty(rp, R_SCALAR); chkcmp(np); break; /* INT */ case DOUBLE '&': case DOUBLE '|': mustty(lp, R_SCALAR); mustty(rp, R_SCALAR); break; /* INT */ case '?': mustty(lp, R_SCALAR); tp = rp->n_tptr; break; case ':': if (same_type(lp->n_tptr, rp->n_tptr)) { tp = lp->n_tptr; break; } mustty(lp, R_SCALAR); mustty(rp, R_SCALAR); tp = colonty(np); break; case '=': mustlval(lp); mustty(lp, R_ASSN); asn_chk(lp->n_tptr, rp); tp = lp->n_tptr; break; case ',': tp = rp->n_tptr; break; default: error("bad binary type"); bad: tp = bas_type(K_INT); } if (isassign(np->e_token)) { /* ignore normal result -- result is left type */ tp = lp->n_tptr; } np->n_tptr = tp; np->n_flags |= N_COPYT; } long conlval(np) NODEP np; { long i; confold(&np,0); if (np->e_token == ICON) { i = np->e_ival; freenode(np); return i; } error("need const expr"); return 0; } conxval(np) NODEP np; { return (int)conlval(np); } confold(npp,spec) NODEP *npp; { NODEP np; NODEP tp, onp; int tok,spl,spr; long l; np = *npp; if (np == NULL) return; switch (np->e_type) { case E_LEAF: lcanon(np,spec); return; case E_UNARY: confold(&np->n_left,0); ucanon(np); return; case E_BIN: confold(&np->n_left,0); confold(&np->n_right,0); if (np->e_token == '?') { tok = np->n_left->e_token; if (tok != ICON) return; l = np->n_left->e_ival; onp = np; tp = np->n_right; /* ':' node */ if (l) { /* take true side */ np = tp->n_left; tp->n_left = NULL; } else { /* take false side */ np = tp->n_right; tp->n_right = NULL; } freenode(onp); *npp = np; return; } bcanon(np); if (np->e_flags & C_AND_A) b_assoc(np); return; case E_SPEC: tok = np->e_token; spl = spr = 0; switch (tok) { case '(': spl = tok; /* new name allowed */ break; case '.': case ARROW: spr = tok; /* look in struct sym.tab. */ break; } confold(&np->n_left,spl); confold(&np->n_right,spr); return; } } newicon(np,x,nf) NODE *np; long x; { np->e_token = ICON; np->e_ival = x; np->e_flags = nf; sprintf(np->n_name, "%ld", x); np->e_type = E_LEAF; if (np->n_left) { freenode(np->n_left); np->n_left = NULL; } if (np->n_right) { freenode(np->n_right); np->n_right = NULL; } } newfcon(np,x,nf) NODE *np; double x; { np->e_token = FCON; np->e_fval = x; np->e_flags = nf; sprintf(np->n_name, FLTFORM, x); np->e_type = E_LEAF; if (np->n_left) { freenode(np->n_left); np->n_left = NULL; } if (np->n_right) { freenode(np->n_right); np->n_right = NULL; } } /* LEAF */ /* sptok is token if E_SPEC node is parent and dont want to look at ID yet */ lcanon(np,sptok) NODE *np; { NODE *tp; NODEP allsyms(); long x; if (np->e_token == ID) { if (sptok) return; see_id(np); return; } if (np->e_token == TSIZEOF) { tp = np->n_tptr; x = tp->t_size; np->n_tptr = NULL; if ((np->n_flags & N_COPYT) == 0) freenode(tp); newicon(np, x, 0); } } /* UNARY */ ucanon(np) NODE *np; { NODE *tp; long x,l; int lflags = 0; if (np->e_token == K_SIZEOF) { tp = np->n_left; confold(&tp,0); form_types(tp); tp = tp->n_tptr; x = tp->t_size; goto out; } if (np->n_left->e_token == FCON) { if (np->e_token == UNARY '-') newfcon(np, -(np->n_left->e_fval)); return; } if (np->n_left->e_token != ICON) return; l = np->n_left->e_ival; lflags = np->n_left->e_flags; switch (np->e_token) { case UNARY '-': x = -l; break; case '~': x = ~l; break; case '!': x = !l; break; default: return; } out: newicon(np, x, lflags); } bcanon(np) register NODE *np; { int ltok, rtok; double l,r; NODEP tp; ltok = np->n_left->e_token; rtok = np->n_right->e_token; if (ltok != ICON && ltok != FCON) return; if (rtok != ICON && rtok != FCON) { /* left is ?CON, right is not */ if (np->e_flags & (C_AND_A|C_NOT_A)) { /* reverse sides - put CON on right */ tp = np->n_left; np->n_left = np->n_right; np->n_right = tp; if (np->e_flags & C_NOT_A) swt_op(np); } return; } if (ltok == ICON && rtok == ICON) { b2i(np); return; } if (ltok == FCON) l = np->n_left->e_fval; else l = (double)np->n_left->e_ival; if (rtok == FCON) r = np->n_right->e_fval; else r = (double)np->n_right->e_ival; b2f(np,l,r); } /* canon for assoc. & comm. op */ /* this code will almost never be executed, but it was fun. */ b_assoc(np) NODEP np; { NODEP lp, rp; int tok; lp = np->n_left; if (lp->e_token != np->e_token) return; /* left is same op as np */ rp = np->n_right; tok = lp->n_right->e_token; if (tok != ICON && tok != FCON) return; /* left.right is ?CON */ tok = rp->e_token; if (tok == ICON || tok == FCON) { /* have 2 CONS l.r and r -- put together on r */ NODEP ep; ep = lp->n_left; np->n_left = ep; np->n_right = lp; lp->n_left = rp; /* can now fold 2 CONS */ bcanon(lp); } else { /* have 1 CON at l.r -- move to top right */ NODEP kp; kp = lp->n_right; lp->n_right = rp; np->n_right = kp; } } /* switch pseudo-commutative op */ swt_op(np) NODEP np; { int newtok; switch (np->e_token) { case LTEQ: newtok = '>'; break; case GTEQ: newtok = '<'; break; case '<': newtok = GTEQ; break; case '>': newtok = LTEQ; break; default: return; } np->e_token = newtok; } /* BINARY 2 ICON's */ b2i(np) register NODE *np; { register long l,r,x; int newflags,lflags; newflags = 0; r = np->n_right->e_ival; newflags = np->n_right->e_flags; l = np->n_left->e_ival; lflags = np->n_left->e_flags; newflags = newflags>lflags ? newflags : lflags; switch (np->e_token) { case '+': x = l+r; break; case '-': x = l-r; break; case '*': x = l*r; break; case '/': x = l/r; break; case '%': x = l%r; break; case '>': x = l>r; break; case '<': x = l=r; break; case GTEQ: x = l<=r; break; case DOUBLE '=': x = l==r; break; case NOTEQ: x = l!=r; break; case '&': x = l&r; break; case '|': x = l|r; break; case '^': x = l^r; break; case DOUBLE '<': x = l<': x = l>>r; break; default: return; } newicon(np, x, newflags); } /* BINARY 2 FCON's */ b2f(np,l,r) register NODE *np; double l,r; { register double x; int ix, isint; isint = 0; switch (np->e_token) { case '+': x = l+r; break; case '-': x = l-r; break; case '*': x = l*r; break; case '/': x = l/r; break; case '>': ix = l>r; isint++; break; case '<': ix = l=r; isint++; break; case GTEQ: ix = l<=r; isint++; break; case DOUBLE '=': ix = l==r; isint++; break; case NOTEQ: ix = l!=r; isint++; break; default: return; } if (isint) newicon(np, (long)ix, 0); else newfcon(np, x); } same_type(a,b) register NODE *a, *b; { more: if (a == b) return 1; if (a == NULL || b == NULL) return 0; if (a->t_token != b->t_token) return 0; if (a->t_token != STAR && a->t_size != b->t_size) return 0; a = a->n_tptr; b = b->n_tptr; goto more; } see_id(np) NODEP np; { NODEP tp; NODEP allsyms(), def_type(); tp = allsyms(np); if (tp == NULL) { errorn("undefined:", np); tp = def_type(); goto out; } switch (tp->e_sc) { case ENUM_SC: newicon(np, tp->e_ival, 0); return; case K_REGISTER: np->e_rno = tp->e_rno; /* fall through */ default: np->e_sc = tp->e_sc; np->e_offs = tp->e_offs; tp = tp->n_tptr; } out: np->n_tptr = tp; np->n_flags |= N_COPYT; /* special conversions */ if (tp->t_token == '(') insptrto(np); } insptrto(np) NODEP np; { NODEP op, copyone(); op = copyone(np); np->n_left = op; np->e_token = UNARY '&'; np->e_type = E_UNARY; strcpy(np->n_name, "&fun"); np->n_flags &= ~N_COPYT; } /* np points to ID or STAR or '.' node tptr is a COPY tptr token is '[' */ see_array(np) NODEP np; { NODEP tp, copyone(); tp = copyone(np); tp->n_left = np->n_left; tp->n_tptr = tp->n_tptr->n_tptr; np->n_left = tp; np->e_token = UNARY '&'; np->e_type = E_UNARY; strcpy(np->n_name, "&ary"); arytoptr(np); /* leave old size np->n_tptr->t_size = SIZE_P; */ }