Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v102a/al40/dri/c068/expr.c
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

1041 lines
23 KiB
C

/*#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) );
}