/*#define DEBUG*/ /* Copyright 1982 Alcyon Corporation 8716 Production Ave. San Diego, Ca. 92121 */ #include "parser.h" int opdontop; int strassign; /* * expr - expression evaluator * This handles all the expression syntax in C. This is a straight- * forward operator-stack/oppri scheme for translating infix into * a binary expression tree. */ char *expr() /* returns 0 or ptr to node*/ { register char *p; register char *opdsave, *oprsave; register int token, op, oppri, i, opdotsave; int type, sc; long size; opdsave = opdp; strassign = 0; oprsave = opp; opdotsave = opdontop; if( !opp || !opdp ) { opp = opstack; opdp = opdstack; } else opp++; opp->o_op = STACKEND; opp->o_pri = STKPRI; opap = exprp; opdontop = 0; while( (token=gettok()) != EOF ) { switch( token ) { /* * the following are the terminal nodes of the expresion tree, * note that when we see a terminal node, we push it and then go * and get the next token. When we see an operator, we need to * check the operator stack to see if we can do a reduction. */ case CINT: if( doopd(cnalloc(INT,cvalue)) ) { exprerr: if( token == SEMI || token == RCURBR ) pbtok(token); error("invalid expression"); opdp = opdsave; opp = oprsave; opdontop = opdotsave; return(0); } continue; case CFLOAT: /*[vlh] 3.4*/ if( doopd(fpcnalloc(FLOAT,clvalue)) ) goto exprerr; continue; case CLONG: if( doopd(lcnalloc(LONG,clvalue)) ) goto exprerr; continue; case SYMBOL: if( !((p=csp)->s_attrib&SDEFINED) ) { if( peek(LPAREN) ) { /*assume function call*/ p->s_sc = EXTERNAL; p->s_type = FUNCTION|INT; } else if( commastop ) /*in initialization?*/ p->s_sc = EXTERNAL; else error("undefined symbol: %.8s",p->s_symbol); p->s_attrib =| SDEFINED; } if (p->s_sc==EXTERNAL || function(p->t_type)) { if (!reducep || p->s_sc==EXTERNAL || peek(LPAREN)) { p = enalloc(p); p->t_sc = EXTERNAL; } else { /* [vlh] 3.4 if (main).... */ p = cnalloc(CINT,1); /* eval function name */ } } else p=snalloc(p->s_type,p->s_sc,p->s_offset,p->s_dp,p->s_ssp); if( doopd(p) ) goto exprerr; continue; case STRING: outtstr(cvalue); if( doopd(snalloc(ARRAY|CHAR,STATIC,cvalue,0,0)) ) goto exprerr; continue; /* * do special checking for unary ops and operators that can be * either unary or binary operators, such as -, &, *, etc. */ case RESWORD: if( cvalue != R_SIZEOF ) { goto exprerr; } token = SIZEOF; case COMPL: case NOT: if( opdontop ) /*can't have: operand unary-op*/ goto exprerr; break; case LBRACK: opdontop = 0; break; case RBRACK: case RPAREN: if( !opdontop ) /*can't be: operator )*/ goto exprerr; break; case PREINC: if( opdontop ) /*assume its lvalue++*/ token = POSTINC; break; case PREDEC: if( opdontop ) /*assume its lvalue--*/ token = POSTDEC; break; case SUB: if(!opdontop) { /*if no operand, assume unary*/ if( peek(CINT) ) { cvalue = -cvalue; continue; } if( peek(CLONG) ) { clvalue = -clvalue; continue; } if( peek(CFLOAT) ) { /*[vlh] 3.4*/ if (!fflag) { /* IEEE format */ if (clvalue & 0x80000000) clvalue =& 0x7fffffff; else clvalue =| 0x80000000; } else /* FFP format */ if (clvalue & 0x80) clvalue =& 0xffffff7f; else clvalue =| 0x80; continue; } token = UMINUS; } break; case AND: if(!opdontop) token = ADDR; break; case MULT: if( !opdontop ) token = INDR; break; /* * for left parenthesis, we need to see if this is a casting operator. */ case LPAREN: if( !opdontop ) { /*see if casting or abstract declarator*/ sc = type = 0; if( gettype(&sc,&type,&size) ) { sc = (type == STRUCT) ? dalloc(size) : cdp; p = snalloc(type,STATIC,0,sc,sc); p->t_type =| declarator(1); if( !next(RPAREN) ) goto exprerr; if( tdp ) p->t_type=addtdtype(tdp,p->t_type,p->t_dp, &(p->t_ssp)); pushopd(p); token = CAST; if( opp->o_op == SIZEOF ) { opdontop++; continue; } } } else /*we've seen (), look for NACALL*/ token = (next(RPAREN)) ? MPARENS : CALL; break; case PERIOD: case APTR: smember++; /*next token needs to be struct membr*/ strucptr[smember+instruct] = csp->s_struc; break; } /* * we have seen an operator, get its info and then check the operator * stack. */ if( binop(token) ) { /* * handle special binary operators, such as CAST and post-inc and * post-dec. */ if(!opdontop) { if( token != PREDEC && token != PREINC && token != CAST ) goto exprerr; } if( token != POSTDEC && token != POSTINC && token != MPARENS ) opdontop = 0; /*this fixes x++ op problem.*/ } oppri = oppriority(token); if( commastop && token == COMMA ) /*need to stop at comma(init)*/ oppri = COLPRI; if( colonstop && token == COLON ) /*need to stop at colon(case)*/ oppri = COLPRI; while( 1 ) { if( oppri > opp->o_pri || (oppri == opp->o_pri && rasop(token)) ) { /* * we have encountered a higher priority (or right-associative) * operator, hence we need to stack it. */ if( ++opp >= &opstack[OPSSIZE] ) ferror("expression too complex"); if( token == POSTINC || token == POSTDEC ) oppri = PSTPRI; else if( token == LPAREN || token == LBRACK || token == CALL ) oppri = CALPRI; opp->o_op = token; opp->o_pri = oppri; break; } /* * we have encountered a lower priority operator, hence we need to * do a reduction. */ op = opp->o_op; opp--; type = CINT; switch( op ) { case STACKEND: /*we accept the expression...*/ pbtok(token); if (!strassign) { if (!maketree(0)) goto exprerr; } if (!(p=popopd())) goto exprerr; opdp = opdsave; opp = oprsave; opdontop = opdotsave; return(p); case LPAREN: /*assure these have matching )*/ case CALL: if( token != RPAREN ) goto exprerr; break; case MPARENS: if( !maketree(NACALL) ) goto exprerr; continue; case LBRACK: if( token != RBRACK ) goto exprerr; if(!maketree(ADD)) /*array[index]->*(array+index)*/ goto exprerr; op = INDR; break; case PREINC: /*turn these into binary operators*/ case POSTINC: /*which in reality they are...*/ case PREDEC: case POSTDEC: pushopd(cnalloc(INT,1)); default: if(!maketree(op)) goto exprerr; continue; /*see if we can reduce some more...*/ } if( op != LPAREN && !maketree(op) ) goto exprerr; break; } } error("unexpected EOF"); return(0); } /* talloc - expression area tree node allocation * Allocates area and checks for overflow.*/ char *talloc(size) /* returns pointer to node*/ int size; /* size of node to alloc*/ { register char *p; p = opap; if( p + size >= &exprarea[EXPSIZE] ) ferror("expression too complex"); opap = p + size; return(p); } /* * enalloc - external name alloc * Allocates an expression tree node for an external name and * copies symbol table info and symbol into tree node. */ char *enalloc(sp) /* returns - none*/ struct symbol *sp; /* pointer to symbol table entry*/ { register struct extnode *ep; ep = talloc(sizeof(*ep)); ep->t_op = SYMBOL; ep->t_sc = sp->s_sc; ep->t_type = sp->s_type; ep->t_dp = sp->s_dp; ep->t_ssp = sp->s_ssp; ep->t_offset = sp->s_offset; symcopy(sp->s_symbol,ep->t_symbol); return(ep); } /* cnalloc - constant node allocation * Allocates a constant tree node and fills the info fields.*/ char *cnalloc(type,value) /* returns pointer to node*/ int type; /* data type*/ int value; /* constant value*/ { register struct conode *cp; cp = talloc(sizeof(*cp)); cp->t_op = CINT; cp->t_type = type; cp->t_dp = 0; cp->t_ssp = 0; cp->t_value = value; return(cp); } /* lcnalloc - long constant node allocation*/ /* Allocates a constant tree node and fills the info fields.*/ char *lcnalloc(type,value) /* returns pointer to node*/ int type; /* data type*/ long value; /* constant value*/ { register struct lconode *cp; cp = talloc(sizeof(*cp)); cp->t_op = CLONG; cp->t_type = type; cp->t_dp = 0; cp->t_ssp = 0; cp->t_lvalue = value; return(cp); } /* fpcnalloc - floating point constant node allocation*/ /* Allocates a constant tree node and fills the info fields.*/ char *fpcnalloc(type,value) /*[vlh] 3.4 returns pointer to node*/ int type; /* data type*/ long value; /* constant value*/ { register struct lconode *cp; cp = talloc(sizeof(*cp)); cp->t_op = CFLOAT; cp->t_type = type; cp->t_dp = 0; cp->t_ssp = 0; cp->t_lvalue = value; return(cp); } /* tnalloc - tree node allocation*/ /* Allocates an operator tree node and fills the info fields*/ char *tnalloc(op,type,dp,ssp,left,right) /* returns pointer to node*/ int op; /* operator*/ int type; /* operator type*/ int dp; /* dimension pointer or other info*/ int ssp; /* structure length pointer*/ char *left; /* left subtree*/ char *right; /* right subtree*/ { register struct tnode *tp; tp = talloc(sizeof(*tp)); tp->t_op = op; tp->t_type = type; tp->t_dp = dp; tp->t_ssp = ssp; tp->t_left = left; tp->t_right = right; return(tp); } /* pushopd - put operand node onto operand stack*/ /* Checks for operand stack overflow.*/ pushopd(tp) /* returns - none*/ struct tnode *tp; /* pointer to tree node to push*/ { #ifdef DEBUG error("pushopd %d",tp->t_op); #endif if( opdp >= &opdstack[OPDSIZE] ) ferror("expression too complex"); *opdp++ = tp; } /* popopd - pop operand stack*/ /* Checks for stack underflow*/ char *popopd() /* returns ptr to top operand*/ { register struct tnode *tp; if( opdp <= &opdstack[0] ) return(0); tp = *--opdp; #ifdef DEBUG error("popopd: %d",tp->t_op); #endif return(tp); } /* doopd - handle constant or symbol node operand*/ /* Pushes node onto operand stack and handles opdontop flag.*/ doopd(tp) /* returns 1 if syntax error, 0 for ok*/ struct tnode *tp; /* pointer to tree node*/ { pushopd(tp); if( opdontop ) return(1); opdontop++; return(0); } /* * This indicates if a conversion operator is needed given the types * of the two operands. The upper diagonal is applied ONLY if this * is an assignment operator and the indexes are swapped so the lower * diagonal is used otherwise. * INT UNSN LONG DOUB PTR */ char cvmap[5][5] { 0, UNSN_INT, LONG_INT, DOUB_INT, PTR_INT, /*INT*/ INT_UNSN, 0, LONG_UNSN, DOUB_UNSN, PTR_UNSN, /*UNSN*/ INT_LONG, UNSN_LONG, 0, DOUB_LONG, PTR_LONG, /*LONG*/ INT_DOUB, UNSN_DOUB, LONG_DOUB, 0, BADCONV, /*DOUB*/ INT_PTR, UNSN_PTR, LONG_PTR, BADCONV, PTR_PTR, /*PTR*/ }; /* * maketree - given operator, takes operands and builds up tree * This takes the given operator, allocates a node for it * and links up the subtrees on the operand stack. A lot of * work is in inserting the proper conversions. */ maketree(op) /* returns success or failure */ int op; /* new root operator*/ { register struct tnode *ltp, *rtp, *p; register int type, ltype, rtype, lconv, conv, pconv, ilen; #ifdef DEBUG error("maketree: op = %d",op); #endif if( binop(op) ) { if(!(rtp=popopd())) return(0); rtype = (rtp=funcref(arrayref(rtp)))->t_type; } if(!(ltp=popopd())) return(0); if( op == SIZEOF ) { /* [vlh] 3.4 ilen */ ilen = dsize(ltp->t_type,ltp->t_dp,ltp->t_ssp); pushopd(cnalloc(INT,ilen)); return(1); } if( op != ADDR ) { ltp = arrayref(ltp); if( op != CALL && op != NACALL ) ltp = funcref(ltp); } if( specops(op,ltp,rtp) ) return( 1 ); ltype = ltp->t_type; if( lintegral(op) ) integral(ltp,LONG); if( rintegral(op) ) integral(rtp,LONG); if( lvalop(op) && ltp->t_op != SYMBOL && ltp->t_op != INDR && ltp->t_op != BFIELD ) error("assignable operand required"); if( unaryop(op) ) { if(!unopeval(op,ltp)) pushopd(tnalloc(op,ltype,ltp->t_dp,ltp->t_ssp,ltp)); return; } if( ltype == STRUCT || rtype == STRUCT ) { if (ltype==STRUCT && rtype==STRUCT && op==ASSIGN) { /*[vlh]*/ pushopd(ltp); maketree(ADDR); pushopd(rtp); maketree(ADDR); maketree(STASSIGN); strassign = 1; return(1); } ltype = rtype = INT; error("illegal structure operation"); } type = ltype; if( rtype == TYPELESS ) { rtp->t_type = rtype = INT; lconv = conv = 0; } else { lconv = ttoconv(ltype); conv = ttoconv(rtype); if (!asgop(op) && conv > lconv) { conv = cvmap[conv][lconv]; lconv = 1; type = rtype; } else { conv = cvmap[lconv][conv]; lconv = 0; } } if( asgop(op) ) { if( (op == ASSIGN || op == FRETURN) && (conv == INT_PTR || conv == UNSN_PTR) && rtp->t_op != CINT ) error("short assigned to pointer"); if( op == ASSIGN || op == CAST ) { switch( conv ) { case INT_PTR: case UNSN_PTR: case PTR_PTR: case PTR_LONG: case LONG_PTR: conv = 0; break; } } } else if( op == COLON && suptype(ltype) != 0 && ltype == rtype ) conv = 0; else if( relop(op) && conv == PTR_PTR ) conv = 0; pconv = 0; if ((relop(op) || op==FRETURN) && alltype(ltype) == (STRUCT | POINTER) && (conv == INT_PTR || conv == LONG_PTR)) /* [vlh] 3.4 */ conv = 0; /* int compare to struct pointer, no conversion */ if( conv == PTR_PTR ) { conv = 0; if( op == SUB ) { type = LONG; pconv++; } else if(op != FRETURN && ( (alltype(ltype) != alltype(rtype) || alltype(ltype) != (POINTER|CHAR)) ) ) conv = BADCONV; } if( conv ) { if( conv == BADCONV ) error("illegal type conversion"); else if( lconv ) { ltp = cvopgen(ltp,type,conv,psize(rtp),op); } else { rtp = cvopgen(rtp,type,conv,psize(ltp),op); } } else if( op == CAST && rtp->t_type != CHAR ) { rtp->t_type = ltp->t_type; rtp->t_ssp = ltp->t_ssp; /* [vlh] 3.4 */ rtp->t_dp = ltp->t_dp; /* [vlh] 3.4 */ } if( relop(op) ) type = INT; if( op == CAST ) pushopd(rtp); else if(!binopeval(op,ltp,rtp)) { if( btype(ltype) == STRUCT || btype(rtype) != STRUCT ) p = ltp; else p = rtp; pushopd(tnalloc(op,type,p->t_dp,p->t_ssp,ltp,rtp)); } if( pconv && ltype != (POINTER|CHAR) ) { if(!(ltp=popopd())) return(0); pushopd(cvopgen(ltp,LONG,PTR_LONG,psize(ltp->t_left),op)); } return(1); } /* specops - handle special operators in building tree*/ specops(op,ltp,rtp) /* returns 1 if op special, 0 otherwise*/ int op; /* operator*/ struct tnode *ltp; /* left subtree pointer*/ struct tnode *rtp; /* right subtree pointer*/ { register int type, sr_size, sl_size; type = ltp->t_type; switch (op) { case 0: break; default: return(0); case APTR: /*expr -> name*/ integral(ltp,LONG); /*we need to turn expr into a*/ ltp->t_type = POINTER|STRUCT; /*pointer to a struct, then use*/ pushopd(ltp); /*expr . name stuff*/ maketree(INDR); ltp = popopd(); /*ltp cannot be 0*/ case PERIOD: /*expr . name*/ if( !(isstel(rtp)) ) error("invalid structure member name"); type = rtp->t_type; if( array(type) ) { type = delspchk(type); rtp->t_dp++; } tadjust(ltp,type,rtp->t_dp,rtp->t_ssp); pushopd(ltp); maketree(ADDR); pushopd(cnalloc(TYPELESS,rtp->t_offset)); maketree(ADD); if( notarray(rtp->t_type) ) maketree(INDR); ltp = popopd(); if( rtp->t_sc == BFIELDCL ) /*ltp cannot be 0*/ ltp = tnalloc(BFIELD,type,rtp->t_dp,rtp->t_ssp,ltp); break; case QMARK: if( rtp->t_op != COLON ) error("invalid ?: operator syntax"); if( ltp->t_op == CINT && rtp->t_left->t_op == CINT && rtp->t_right->t_op == CINT ) ltp->t_value = (ltp->t_value ? rtp->t_left->t_value : rtp->t_right->t_value); else ltp = tnalloc(op,rtp->t_type,0,0,ltp,rtp); break; case LAND: case LOR: case COMMA: /*don't need conversions here*/ ltp = tnalloc(op,INT,0,0,ltp,rtp); break; case INDR: if( ltp->t_op == ADDR ) /**& is null op*/ ltp = ltp->t_left; else { if( function(type) ) error("indirection on function invalid"); ltp = tnalloc(INDR,delspchk(type),ltp->t_dp,ltp->t_ssp,ltp); } break; case STASSIGN: /*[vlh]*/ sr_size = psize(rtp); sl_size = psize(ltp); if( sl_size >= sr_size ) ltp = tnalloc(STASSIGN,sr_size,0,0,ltp,rtp); else error("invalid structure assignment"); break; case NACALL: case CALL: if( notfunction(type) ) error("illegal call"); ltp = tnalloc(op,delspchk(type),ltp->t_dp,ltp->t_ssp,ltp,rtp); break; case ADDR: if( ltp->t_op == INDR ) { /*&* is null op*/ /* ltp->t_left->t_type = addsp(type,POINTER);*/ /* ltp->t_left->t_dp = ltp->t_dp;*/ /* ltp->t_left->t_ssp = ltp->t_ssp;*/ ltp = ltp->t_left; } else { if( ltp->t_op != SYMBOL ) error("& operand illegal"); else if( ltp->t_sc == REGISTER ) error("address of register"); ltp = tnalloc(ADDR,addsp(type,POINTER),ltp->t_dp,ltp->t_ssp, ltp); } break; } pushopd(ltp); return(1); } /* cvopgen - generate a conversion operator*/ /* Generates conversions necessary for integers, pointers and longs.*/ char *cvopgen(tp,type,conv,len,op) /* returns pointer to conv node*/ struct tnode *tp; /* pointer to node to do conversion*/ int type; /* type to convert to*/ int conv; /* specified conversion*/ long len; /* object length [vlh] 3.4 i=>l */ int op; /* for cast operator*/ { register struct tnode *rtp; register int cop, ilen; switch(conv) { case INT_PTR: case UNSN_PTR: if( op == CAST || op == FRETURN ) { cop = INT2L; /*of the ptd to objects length plus*/ if( len != 1L ) { /*an integer to long covnversion*/ ilen = len; rtp = cnalloc(INT,ilen); tp = tnalloc(MULT,type,0,0,tp,rtp); } break; } case PTR_LONG: /*need to generate mult or div*/ case LONG_PTR: /*of the ptd to objects length*/ if( len == 1 ) return(tp); ilen = len; cop = (conv == PTR_LONG ? DIV : MULT); rtp = cnalloc(INT,ilen); break; case INT_LONG: case UNSN_LONG: cop = INT2L; break; case INT_DOUB: /*[vlh] 3.4*/ case UNSN_DOUB: cop = INT2F; break; case LONG_DOUB: /*[vlh] 3.4*/ cop = LONG2F; break; case DOUB_LONG: /*[vlh] 3.4*/ cop = FLOAT2L; break; case DOUB_INT: /*[vlh] 3.4*/ case DOUB_UNSN: cop = FLOAT2I; break; case LONG_INT: case LONG_UNSN: cop = LONG2I; break; default: error("invalid conversion"); return(tp); } return( tnalloc(cop,type,0,0,tp,rtp) ); } /* tadjust - expression tree type adjustment*/ /* Adjusts the types of subtrees to agree with the top of the tree.*/ tadjust(tp,type,dp,ssp) /* returns - none*/ struct tnode *tp; /* pointer to tree*/ int type; /* type to adjust to*/ int dp; /* dimension pointer or info*/ int ssp; /* structure pointer*/ { register int op; tp->t_type = type; if( dp >= 0 ) { tp->t_dp = dp; tp->t_ssp = ssp; } if( (op=tp->t_op) == ADDR ) type = delspchk(type); else if( op == INDR ) type = addsp(type,POINTER); else if( op != ADD && op != SUB ) return; tadjust(tp->t_left,type,dp,ssp); } /* funcref - handle tree function reference*/ /* Turns a reference to a function into the address of the function.*/ char *funcref(tp) /* returns pointer to node*/ struct tnode *tp; /* pointer to old node*/ { if( function(tp->t_type) ) tp = tnalloc(ADDR,addsp(tp->t_type,POINTER),tp->t_dp,tp->t_ssp,tp); return(tp); } /* arrayref - handle tree array reference*/ /* Turns a reference to an array into the address of the array.*/ char *arrayref(tp) /* returns pointer to tree node*/ struct tnode *tp; /* tree node pointer*/ { if( array(tp->t_type) && !(isstel(tp)) ) { tp->t_dp++; pushopd(tp); tadjust(tp,delspchk(tp->t_type),-1,0); maketree(ADDR); tp = popopd(); /*tp cannot be 0*/ } return(tp); } /* integral - checks operand for integral type*/ /* This checks for needing an integral operand.*/ integral(tp,atype) /* returns - none*/ struct tnode *tp; /* pointer to tree node*/ int atype; /* alternate type allowable*/ { register int type; if( (type=tp->t_type) != INT && type != UNSIGNED && type != CHAR && !suptype(type) && type != atype ) error("invalid operand type"); } /* ttoconv - maps normal type into conversion table type*/ ttoconv(type) /* returns conversion type*/ int type; /* type to convert*/ { switch(type) { case CHAR: case INT: return(0); case UNSIGNED: return(1); case LONG: return(2); case FLOAT: case DOUBLE: return(3); default: return(4); } } /* binopeval - does binary operator constant expression evaluation*/ /* Does the constant expression evaluation for binary operators.*/ binopeval(op,ltp,rtp) /* returns 1 if done, 0 if not*/ int op; /* operator to evaluate*/ struct tnode *ltp; /* pointer to left subtree*/ struct tnode *rtp; /* pointer to right subtree*/ { register int lvalue, rvalue; if( ltp->t_op != CINT ) return(0); lvalue = ltp->t_value; if( rtp->t_op != CINT ) return(0); rvalue = rtp->t_value; switch (op) { case ADD: lvalue =+ rvalue; break; case SUB: lvalue =- rvalue; break; case MULT: lvalue =* rvalue; break; case DIV: lvalue =/ rvalue; break; case MOD: lvalue =% rvalue; break; case AND: lvalue =& rvalue; break; case OR: lvalue =| rvalue; break; case XOR: lvalue =^ rvalue; break; case LSH: lvalue =<< rvalue; break; case RSH: lvalue =>> rvalue; break; case EQUALS: lvalue = (lvalue == rvalue); break; case NEQUALS: lvalue = (lvalue != rvalue); break; case GREAT: lvalue = (lvalue > rvalue); break; case LESS: lvalue = (lvalue < rvalue); break; case GREATEQ: lvalue = (lvalue >= rvalue); break; case LESSEQ: lvalue = (lvalue <= rvalue); break; default: return(0); } ltp->t_value = lvalue; pushopd(ltp); return(1); } /* unopeval - unary operator constant expression evaluation*/ /* Does constant expression evaluation for unary operators.*/ unopeval(op,tp) /* returns 1 if done, 0 otherwise*/ int op; /* operator to evaluate*/ struct tnode *tp; /* pointer to subexpression*/ { register int value; if( tp->t_op != CINT ) return(0); value = tp->t_value; switch( op ) { case COMPL: value = ~ value; break; case UMINUS: value = - value; break; case NOT: value = ! value; break; default: return(0); } tp->t_value = value; pushopd(tp); return(1); } /* cexpr - evaluate a constant integer expression*/ /* Used in evaluating array bounds, bit field numbers, etc.*/ cexpr() { register struct tnode *tp; register char *savep; savep = exprp; exprp = opap; commastop++; if( (tp=expr()) && tp->t_op != CINT ) error("constant required"); commastop--; exprp = savep; return( tp->t_value ); } /* delspchk - delete one special reference and check if non-zero*/ delspchk(type) /*returns new special type*/ int type; /* type to modify*/ { if(!(suptype(type))) error("bad indirection"); return( delsp(type) ); } /* psize - return size of object ptd at by pointer*/ long /* [vlh] 3.4 int => long */ psize(tp) /* returns size of object in bytes*/ struct tnode *tp; /* pointer to tree node*/ { if ( !(suptype(tp->t_type)) ) /* what case ??? */ return(1); return( dsize(delsp(tp->t_type),tp->t_dp,tp->t_ssp) ); }