2236 lines
40 KiB
C
2236 lines
40 KiB
C
# include "mfile1.h"
|
|
static TWORD orgtleft;
|
|
static int convasgflg;
|
|
|
|
/* some special actions, used in finding the type of nodes */
|
|
# define NCVT 01
|
|
# define PUN 02
|
|
# define TYPL 04
|
|
# define TYPR 010
|
|
# define TYMATCH 040
|
|
# define LVAL 0100
|
|
# define CVTO 0200
|
|
# define CVTL 0400
|
|
# define CVTR 01000
|
|
# define PTMATCH 02000
|
|
# define OTHER 04000
|
|
# define NCVTR 010000
|
|
|
|
/* node conventions:
|
|
**
|
|
** NAME: rval>0 is stab index for external
|
|
** rval<0 is -inlabel number
|
|
** lval is offset in address units
|
|
** (NAME really means "STATIC VARIABLE")
|
|
** ICON: lval has the value
|
|
** rval has the STAB index, or - label number,
|
|
** if a name whose address is in the constant
|
|
** rval = NONAME means no name
|
|
** VAUTO: automatic name: lval has offset in address units
|
|
** VPARAM: parameter: lval has offset in address units
|
|
** REG: rval is reg. number
|
|
**
|
|
*/
|
|
|
|
TWORD
|
|
indtype( t )
|
|
register TWORD t;
|
|
{
|
|
/* return the type of an intermediate expression of type t */
|
|
switch( t )
|
|
{
|
|
|
|
case CHAR:
|
|
case SHORT:
|
|
return( INT );
|
|
|
|
case UCHAR:
|
|
case USHORT:
|
|
return( UNSIGNED );
|
|
|
|
case FLOAT:
|
|
return( DOUBLE );
|
|
|
|
}
|
|
return( t );
|
|
}
|
|
|
|
int bdebug = 0;
|
|
extern ddebug;
|
|
|
|
# ifndef XI
|
|
NODE *
|
|
xicolon( l, r1, r2 ) register NODE *l, *r1, *r2;
|
|
|
|
{
|
|
uerror( "syntax error: colon in subscript" );
|
|
tfree( r2 );
|
|
return( buildtree( LB, l, r1 ) );
|
|
}
|
|
# endif
|
|
|
|
NODE *
|
|
buildtree( o, l, r )
|
|
register NODE *l, *r;
|
|
register o;
|
|
{
|
|
register NODE *p, *q;
|
|
register actions;
|
|
register opty;
|
|
register struct symtab *sp;
|
|
register NODE *lr, *ll;
|
|
int i;
|
|
|
|
# ifndef NODBG
|
|
if( bdebug )
|
|
printf( "buildtree( %s, %d, %d )\n", opst[o], l-node, r-node );
|
|
# endif
|
|
|
|
/* special case to recognize subscripting explicitly */
|
|
|
|
# ifdef XI
|
|
if( o == LB && l->tn.type == LONG )
|
|
return( xicolon( l, r, (NODE *) 0 ) );
|
|
# endif
|
|
|
|
if( o == LB ) return( buildtree( STAR, buildtree( PLUS, l, r ), NIL ) );
|
|
opty = optype(o);
|
|
|
|
/* check for constants */
|
|
|
|
if( o == NOT && l->in.op == ICON && hflag )
|
|
{
|
|
werror( "constant argument to NOT" );
|
|
}
|
|
|
|
else if( o==UNARY MINUS && l->in.op==FCON )
|
|
{
|
|
l->fpn.dval = -l->fpn.dval;
|
|
return(l);
|
|
}
|
|
|
|
else if( o==QUEST && l->in.op==ICON && l->tn.rval==NONAME )
|
|
{
|
|
l->in.op = FREE;
|
|
r->in.op = FREE;
|
|
if( l->tn.lval )
|
|
{
|
|
tfree( r->in.right );
|
|
return( r->in.left );
|
|
}
|
|
else
|
|
{
|
|
tfree( r->in.left );
|
|
return( r->in.right );
|
|
}
|
|
}
|
|
|
|
else if( (o==ANDAND || o==OROR) && (l->in.op==ICON||r->in.op==ICON) )
|
|
goto ccwarn;
|
|
|
|
else if( opty == BITYPE && l->in.op == ICON && r->in.op == ICON )
|
|
{
|
|
|
|
switch( o )
|
|
{
|
|
|
|
case ULT:
|
|
case UGT:
|
|
case ULE:
|
|
case UGE:
|
|
case LT:
|
|
case GT:
|
|
case LE:
|
|
case GE:
|
|
case EQ:
|
|
case NE:
|
|
case ANDAND:
|
|
case OROR:
|
|
case CBRANCH:
|
|
|
|
ccwarn:
|
|
if( hflag ) werror( "constant in conditional context" );
|
|
}
|
|
}
|
|
|
|
/* we make a real node, and look for shrinking later */
|
|
|
|
p = block( o, l, r, INT, 0, INT );
|
|
|
|
actions = opact(p);
|
|
# ifdef MYOPACT
|
|
actions = MYOPACT(p,actions);
|
|
# endif
|
|
|
|
if( actions&LVAL )
|
|
{
|
|
/* check left descendent */
|
|
if( notlval(p->in.left) )
|
|
{
|
|
uerror( "illegal lhs of assignment operator" );
|
|
}
|
|
}
|
|
|
|
if( actions & NCVTR )
|
|
{
|
|
p->in.left = pconvert( p->in.left );
|
|
}
|
|
else if( !(actions & NCVT ) )
|
|
{
|
|
switch( opty )
|
|
{
|
|
|
|
case BITYPE:
|
|
p->in.right = pconvert( p->in.right );
|
|
case UTYPE:
|
|
if( !(actions&LVAL) )
|
|
p->in.left = pconvert( p->in.left );
|
|
|
|
}
|
|
}
|
|
|
|
if( (actions&PUN) && (o!=CAST||cflag) )
|
|
{
|
|
chkpun(p);
|
|
}
|
|
|
|
if( actions & (TYPL|TYPR) )
|
|
{
|
|
|
|
q = (actions&TYPL) ? p->in.left : p->in.right;
|
|
|
|
p->in.type = q->in.type;
|
|
p->fn.cdim = q->fn.cdim;
|
|
p->fn.csiz = q->fn.csiz;
|
|
}
|
|
|
|
if( actions & CVTL ) p = convert( p, CVTL );
|
|
if( actions & CVTR ) p = convert( p, CVTR );
|
|
|
|
if( actions & TYMATCH ) p = tymatch(p);
|
|
/* hier z.B. (int a) -= (unsigned b) => in (unsigned -=) umgebaut und convasgflg gesetzt fuer Ruecknahme, s. vor return(p)
|
|
*/
|
|
|
|
if( actions & PTMATCH ) p = ptmatch(p);
|
|
|
|
if( actions & SPFLG ) p = clocal(p);
|
|
|
|
if( actions & OTHER )
|
|
{
|
|
l = p->in.left;
|
|
r = p->in.right;
|
|
|
|
switch(o)
|
|
{
|
|
|
|
case NAME:
|
|
sp = &stab[idname];
|
|
if( sp->stype == UNDEF )
|
|
{
|
|
lerror( "%s undefined", sp->sname );
|
|
/* make p look reasonable */
|
|
p->in.type = p->fn.cdim = p->fn.csiz = INT;
|
|
p->tn.rval = idname;
|
|
p->tn.lval = 0;
|
|
defid( p, SNULL );
|
|
break;
|
|
}
|
|
p->in.type = sp->stype;
|
|
p->fn.cdim = sp->dimoff;
|
|
p->fn.csiz = sp->sizoff;
|
|
/* special case: MOETY is really an ICON... */
|
|
if( p->in.type == MOETY )
|
|
{
|
|
p->tn.rval = NONAME;
|
|
p->tn.lval = sp->offset;
|
|
p->fn.cdim = 0;
|
|
p->in.type = ENUMTY;
|
|
p->in.op = ICON;
|
|
}
|
|
else
|
|
{
|
|
switch( sp->sclass )
|
|
{
|
|
|
|
case AUTO:
|
|
p->in.op = VAUTO;
|
|
p->tn.rval = NONAME;
|
|
p->tn.lval = BITOOR(sp->offset);
|
|
break;
|
|
|
|
case PARAM:
|
|
p->in.op = VPARAM;
|
|
p->tn.rval = NONAME;
|
|
p->tn.lval = BITOOR(sp->offset);
|
|
break;
|
|
|
|
case REGISTER:
|
|
p->in.op = REG;
|
|
p->tn.lval = 0;
|
|
p->tn.rval = sp->offset;
|
|
break;
|
|
|
|
case ULABEL:
|
|
case LABEL:
|
|
case STATIC:
|
|
if( sp->slevel != 0 )
|
|
{
|
|
p->tn.lval = 0;
|
|
p->tn.rval = -sp->offset;
|
|
break;
|
|
}
|
|
/* FALLTHRU */
|
|
|
|
default:
|
|
p->tn.lval = 0;
|
|
p->tn.rval = idname;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ICON:
|
|
p->in.type = INT;
|
|
p->fn.cdim = 0;
|
|
p->fn.csiz = INT;
|
|
break;
|
|
|
|
case STRING:
|
|
p->in.op = NAME;
|
|
p->in.type = CHAR+ARY;
|
|
p->tn.lval = 0;
|
|
p->tn.rval = NOLAB;
|
|
p->fn.cdim = curdim;
|
|
p->fn.csiz = CHAR;
|
|
break;
|
|
|
|
case FCON:
|
|
p->tn.lval = 0;
|
|
p->tn.rval = 0;
|
|
p->in.type = DOUBLE;
|
|
p->fn.cdim = 0;
|
|
p->fn.csiz = DOUBLE;
|
|
break;
|
|
|
|
case STREF:
|
|
/* p->x turned into *(p+offset) */
|
|
/* rhs must be a name; check correctness */
|
|
|
|
i = r->tn.rval;
|
|
if(i<0 || i>=SYMTSZ || ((sp= &stab[i])->sclass != MOS &&
|
|
sp->sclass != MOU && !(sp->sclass&FIELD)) )
|
|
{
|
|
uerror( "structure/union member required" );
|
|
break;
|
|
}
|
|
else
|
|
/* if this name is non-unique, find right one */
|
|
if( stab[i].sflags&SNONUNIQ && (l->in.type==PTR+STRTY ||
|
|
l->in.type == PTR+UNIONTY) &&
|
|
(l->fn.csiz+1) >= 0 )
|
|
{
|
|
/* nonunique name && structure defined */
|
|
char * memnam, * tabnam;
|
|
OFFSZ j;
|
|
OFFSZ memi;
|
|
j=dimtab[l->fn.csiz+1];
|
|
for( ; (memi=dimtab[j]) >= 0; ++j )
|
|
{
|
|
tabnam = stab[memi].sname;
|
|
memnam = stab[i].sname;
|
|
# ifndef NODBG
|
|
if( ddebug>1 )
|
|
{
|
|
printf("member %s==%s?\n",
|
|
memnam, tabnam);
|
|
}
|
|
# endif
|
|
if( stab[memi].sflags & SNONUNIQ )
|
|
{
|
|
if ( memnam != tabnam )
|
|
continue;
|
|
r->tn.rval = i = memi;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
if( memi < 0 )
|
|
lerror("illegal member use: %s",
|
|
stab[i].sname);
|
|
}
|
|
else
|
|
{
|
|
register j;
|
|
if( l->in.type != PTR+STRTY &&
|
|
l->in.type != PTR+UNIONTY )
|
|
{
|
|
if( stab[i].sflags & SNONUNIQ )
|
|
{
|
|
uerror(
|
|
"nonunique name demands struct/union or struct/union pointer" );
|
|
}
|
|
else werror(
|
|
"struct/union or struct/union pointer required" );
|
|
}
|
|
else if( (j=l->fn.csiz+1)<0 )
|
|
cerror( "undefined structure or union");
|
|
else if( !chkstr( i, dimtab[j],
|
|
DECREF(l->in.type) ) )
|
|
{
|
|
werror( "illegal member use: %s",
|
|
stab[i].sname );
|
|
}
|
|
}
|
|
p = stref( p );
|
|
break;
|
|
|
|
case STAR:
|
|
if( l->in.op == UNARY AND )
|
|
{
|
|
p->in.op = l->in.op = FREE;
|
|
p = l->in.left;
|
|
}
|
|
if( !ISPTR(l->in.type) ) uerror("illegal indirection");
|
|
p->in.type = DECREF(l->in.type);
|
|
p->fn.cdim = l->fn.cdim;
|
|
p->fn.csiz = l->fn.csiz;
|
|
break;
|
|
|
|
case UNARY AND:
|
|
switch( l->in.op )
|
|
{
|
|
|
|
case STAR:
|
|
p->in.op = l->in.op = FREE;
|
|
p = l->in.left;
|
|
case NAME:
|
|
case VAUTO:
|
|
case VPARAM:
|
|
case RNODE:
|
|
case STCALL:
|
|
case UNARY STCALL:
|
|
p->in.type = INCREF( l->in.type );
|
|
p->fn.cdim = l->fn.cdim;
|
|
p->fn.csiz = l->fn.csiz;
|
|
break;
|
|
|
|
case COMOP:
|
|
lr = buildtree( UNARY AND, l->in.right, NIL );
|
|
p->in.op = l->in.op = FREE;
|
|
p = buildtree( COMOP, l->in.left, lr );
|
|
break;
|
|
|
|
case QUEST:
|
|
lr = buildtree( UNARY AND,
|
|
l->in.right->in.right, NIL );
|
|
ll = buildtree( UNARY AND,
|
|
l->in.right->in.left, NIL );
|
|
p->in.op = l->in.op = l->in.right->in.op = FREE;
|
|
p = buildtree( QUEST, l->in.left,
|
|
buildtree( COLON, ll, lr ) );
|
|
break;
|
|
|
|
default:
|
|
uerror( "unacceptable operand of &" );
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case RETURN:
|
|
case ASSIGN:
|
|
case CAST:
|
|
/* structure assignment */
|
|
/* take the addresses of the two sides; then make an
|
|
** operator using STASG and
|
|
** the addresses of left and right
|
|
*/
|
|
|
|
{
|
|
register TWORD t;
|
|
register d, s;
|
|
OFFSZ sz;
|
|
|
|
if( l->fn.csiz != r->fn.csiz )
|
|
uerror(
|
|
"assignment of different structures" );
|
|
|
|
r = buildtree( UNARY AND, r, NIL );
|
|
l = buildtree( UNARY AND, l, NIL );
|
|
t = r->in.type;
|
|
d = r->fn.cdim;
|
|
s = r->fn.csiz;
|
|
#ifdef ENDSTRUCT
|
|
sz = tsize( STRTY, d, s );
|
|
l = aadjust( l, sz );
|
|
r = aadjust( r, sz );
|
|
#endif
|
|
|
|
l = block( STASG, l, r, t, d, s );
|
|
|
|
if( o == RETURN )
|
|
{
|
|
p->in.op = FREE;
|
|
p = l;
|
|
break;
|
|
}
|
|
|
|
p->in.op = STAR;
|
|
p->in.left = clocal(l);
|
|
p->in.right = NIL;
|
|
break;
|
|
}
|
|
case COLON:
|
|
/* structure colon */
|
|
|
|
if( l->fn.csiz != r->fn.csiz )
|
|
uerror( "type clash in conditional" );
|
|
break;
|
|
|
|
case CALL:
|
|
i = 0;
|
|
p->in.right = r = strargs( p->in.right, &i );
|
|
if( i > maxarg ) maxarg = i;
|
|
case UNARY CALL:
|
|
if( !ISPTR(l->in.type)) uerror("illegal function");
|
|
p->in.type = DECREF(l->in.type);
|
|
if( !ISFTN(p->in.type)) uerror("illegal function");
|
|
p->in.type = DECREF( p->in.type );
|
|
p->fn.cdim = l->fn.cdim;
|
|
p->fn.csiz = l->fn.csiz;
|
|
if( l->in.op == UNARY AND &&
|
|
l->in.left->in.op == NAME &&
|
|
l->in.left->tn.rval >= 0 &&
|
|
l->in.left->tn.rval != NONAME &&
|
|
((i=stab[l->in.left->tn.rval].sclass)==FORTRAN
|
|
|| i == UFORTRAN ) )
|
|
{
|
|
p->in.op += (FORTCALL-CALL);
|
|
}
|
|
if( p->in.type == STRTY || p->in.type == UNIONTY )
|
|
{
|
|
/* function returning structure */
|
|
/* function really returns ptr with * */
|
|
|
|
# ifdef ARGSRET
|
|
/* set aside argument space for return val */
|
|
i = tsize( p->in.type, p->fn.cdim, p->fn.csiz );
|
|
/* alignment??? */
|
|
if( i > maxarg ) maxarg = i;
|
|
# endif
|
|
p->in.op += STCALL-CALL;
|
|
p->in.type = INCREF( p->in.type );
|
|
p = buildtree( STAR, p, NIL );
|
|
break;
|
|
}
|
|
|
|
/* fix up type of return value from call */
|
|
{
|
|
register TWORD t;
|
|
t = indtype( p->tn.type );
|
|
if( t != p->tn.type )
|
|
{
|
|
p->fn.csiz = p->tn.type = t;
|
|
}
|
|
}
|
|
# ifdef ARGALLRET
|
|
/* set aside argument space for return val */
|
|
i = tsize( p->in.type, p->fn.cdim, p->fn.csiz );
|
|
/* alignment??? */
|
|
if( i > maxarg ) maxarg = i;
|
|
# endif
|
|
break;
|
|
|
|
default:
|
|
cerror( "other code %d", o );
|
|
}
|
|
|
|
}
|
|
|
|
if( actions & CVTO ) p = oconvert(p);
|
|
p = clocal(conval(p));
|
|
|
|
# ifndef NODBG
|
|
if( bdebug ) eprint(p);
|
|
# endif
|
|
if( convasgflg && asgop(p->in.op) && p->in.left->in.op==CONV )
|
|
p = makety(p,orgtleft,0,(int)orgtleft);
|
|
return(p);
|
|
|
|
}
|
|
|
|
NODE *
|
|
strargs( p, off )
|
|
register NODE *p;
|
|
register *off;
|
|
{
|
|
/* rewrite arguments */
|
|
/* allocate the arguments at *off, and update *off */
|
|
register TWORD t;
|
|
|
|
t = p->fn.type;
|
|
if( p->in.op == CM )
|
|
{
|
|
p->in.left = strargs( p->in.left, off );
|
|
p->in.right = strargs( p->in.right, off );
|
|
return( p );
|
|
}
|
|
|
|
p = block( STARG, p, NIL, t, p->fn.cdim, p->fn.csiz );
|
|
if( t == STRTY || t == UNIONTY )
|
|
{
|
|
p->in.left = buildtree( UNARY AND, p->in.left, NIL );
|
|
}
|
|
else
|
|
{
|
|
p->in.op = FUNARG;
|
|
}
|
|
SETOFF( *off, talign( t, p->fn.csiz ) );
|
|
p->tn.rval = *off;
|
|
*off += tsize( t, p->fn.cdim, p->fn.csiz );
|
|
return( clocal(p) );
|
|
}
|
|
|
|
chkstr( i, j, type )
|
|
register TWORD type;
|
|
register i;
|
|
OFFSZ j;
|
|
{
|
|
/* is the MOS or MOU at stab[i] OK for strict reference by a ptr */
|
|
/* i has been checked to contain a MOS or MOU */
|
|
/* j is the index in dimtab of the members... */
|
|
register k, kk;
|
|
|
|
extern int ddebug;
|
|
|
|
# ifndef NODBG
|
|
if( ddebug > 1 ) printf( "chkstr( %s(%d), %ld )\n", stab[i].sname, i, j );
|
|
# endif
|
|
if( (k = j) < 0 ) uerror( "undefined structure or union" );
|
|
else
|
|
{
|
|
for( ; (kk = dimtab[k] ) >= 0; ++k )
|
|
{
|
|
if( kk >= SYMTSZ )
|
|
{
|
|
cerror( "gummy structure" );
|
|
return(1);
|
|
}
|
|
if( kk == i ) return( 1 );
|
|
switch( stab[kk].stype )
|
|
{
|
|
|
|
case STRTY:
|
|
case UNIONTY:
|
|
if( type == STRTY ) continue; /* no recursive looking for strs */
|
|
if( hflag && chkstr( i, dimtab[stab[kk].sizoff+1], stab[kk].stype ) )
|
|
{
|
|
if( stab[kk].sname[0] == '$' ) return(0); /* $FAKE */
|
|
werror(
|
|
"illegal member use: perhaps %s.%s?",
|
|
stab[kk].sname, stab[i].sname);
|
|
return(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
NODE *
|
|
conval( p )
|
|
register NODE *p;
|
|
{
|
|
register NODE *l, *r;
|
|
register o, i, f, u;
|
|
register CONSZ val;
|
|
|
|
f = (p->tn.type==FLOAT || p->tn.type == DOUBLE);
|
|
u = ISUNSIGNED(p->tn.type);
|
|
|
|
switch( optype(o = p->tn.op) )
|
|
{
|
|
case BITYPE:
|
|
l = p->in.left;
|
|
r = p->in.right;
|
|
break;
|
|
|
|
case UTYPE:
|
|
r = l = p->in.left;
|
|
break;
|
|
|
|
case LTYPE:
|
|
return( p );
|
|
}
|
|
|
|
if( l->tn.op != ( f ? FCON : ICON ) ) return( p );
|
|
if( r->tn.op != ( f ? FCON : ICON ) ) return( p );
|
|
|
|
if( !f )
|
|
{
|
|
/* weed out unprofitable cases */
|
|
val = r->tn.lval;
|
|
if( l->tn.rval != NONAME && r->tn.rval != NONAME ) return(p);
|
|
if( r->tn.rval != NONAME && o!=PLUS ) return(p);
|
|
if( l->tn.rval != NONAME && o!=PLUS && o!=MINUS ) return(p);
|
|
}
|
|
else if( logop(o) ) return( p );
|
|
|
|
switch( o )
|
|
{
|
|
|
|
case PLUS:
|
|
if( f )
|
|
{
|
|
l->fpn.dval += r->fpn.dval;
|
|
break;
|
|
}
|
|
l->tn.lval += val;
|
|
if( l->tn.rval == NONAME )
|
|
{
|
|
l->tn.rval = r->tn.rval;
|
|
l->in.type = r->in.type;
|
|
}
|
|
break;
|
|
|
|
case MINUS:
|
|
if( f ) l->fpn.dval -= r->fpn.dval;
|
|
else l->tn.lval -= val;
|
|
break;
|
|
|
|
case MUL:
|
|
if( f ) l->fpn.dval *= r->fpn.dval;
|
|
else l->tn.lval *= val;
|
|
break;
|
|
|
|
case DIV:
|
|
if( f )
|
|
{
|
|
if( r->fpn.dval == 0. ) uerror( "division by 0" );
|
|
else l->fpn.dval /= r->fpn.dval;
|
|
}
|
|
else
|
|
{
|
|
if( val == 0 ) uerror( "division by 0" );
|
|
else if( u )
|
|
l->tn.lval = (unsigned long)l->tn.lval / val;
|
|
else l->tn.lval /= val;
|
|
}
|
|
break;
|
|
|
|
case MOD:
|
|
if( val == 0 ) uerror( "division by 0" );
|
|
else if( u ) l->tn.lval = (unsigned long)l->tn.lval % val;
|
|
else l->tn.lval %= val;
|
|
break;
|
|
|
|
case AND:
|
|
l->tn.lval &= val;
|
|
break;
|
|
|
|
case OR:
|
|
l->tn.lval |= val;
|
|
break;
|
|
|
|
case ER:
|
|
l->tn.lval ^= val;
|
|
break;
|
|
|
|
case LS:
|
|
i = val;
|
|
l->tn.lval = l->tn.lval << i;
|
|
break;
|
|
|
|
case RS:
|
|
i = val;
|
|
if( u ) l->tn.lval = (unsigned long)l->tn.lval >> i;
|
|
else l->tn.lval = l->tn.lval >> i;
|
|
break;
|
|
|
|
case UNARY MINUS:
|
|
if( f ) l->fpn.dval = -l->fpn.dval;
|
|
else l->tn.lval = - l->tn.lval;
|
|
break;
|
|
|
|
case COMPL:
|
|
l->tn.lval = ~l->tn.lval;
|
|
break;
|
|
|
|
case NOT:
|
|
if( l->tn.type == FLOAT || l->tn.type == DOUBLE )
|
|
{
|
|
l->tn.op = ICON;
|
|
l->tn.lval = !l->fpn.dval;
|
|
}
|
|
else l->tn.lval = !l->tn.lval;
|
|
break;
|
|
|
|
case LT:
|
|
l->tn.lval = l->tn.lval < val;
|
|
break;
|
|
|
|
case LE:
|
|
l->tn.lval = l->tn.lval <= val;
|
|
break;
|
|
|
|
case GT:
|
|
l->tn.lval = l->tn.lval > val;
|
|
break;
|
|
|
|
case GE:
|
|
l->tn.lval = l->tn.lval >= val;
|
|
break;
|
|
|
|
case ULT:
|
|
l->tn.lval = (l->tn.lval-val)<0;
|
|
break;
|
|
|
|
case ULE:
|
|
l->tn.lval = (l->tn.lval-val)<=0;
|
|
break;
|
|
|
|
case UGE:
|
|
l->tn.lval = (l->tn.lval-val)>=0;
|
|
break;
|
|
|
|
case UGT:
|
|
l->tn.lval = (l->tn.lval-val)>0;
|
|
break;
|
|
|
|
case EQ:
|
|
l->tn.lval = l->tn.lval == val;
|
|
break;
|
|
|
|
case NE:
|
|
l->tn.lval = l->tn.lval != val;
|
|
break;
|
|
|
|
default:
|
|
return(p);
|
|
}
|
|
|
|
if( l != r ) r->tn.op = FREE; /* don't clobber unary answer */
|
|
l = makety( l, p->tn.type, p->fn.cdim, p->fn.csiz );
|
|
p->tn.op = FREE;
|
|
return( l );
|
|
}
|
|
|
|
chkpun(p)
|
|
register NODE *p;
|
|
{
|
|
/* checks p for the existance of a pun */
|
|
/* this is called when the op of p is ASSIGN, RETURN, CAST, COLON,
|
|
** or relational
|
|
*/
|
|
|
|
/* one case is when enumerations are used: this applies only to lint */
|
|
/* in the other case, one operand is a pointer, the other integer */
|
|
/* we check that this integer is in fact a constant zero... */
|
|
/* if it is, we redo the type of the 0 to match the other side */
|
|
|
|
/* with ASSIGN, assignment of pointer to integer is illegal */
|
|
/* this falls out, because the LHS is never 0 */
|
|
|
|
register NODE *q1, *q2;
|
|
register t1, t2;
|
|
register d1, d2;
|
|
|
|
q1 = p->in.left;
|
|
q2 = p->in.right;
|
|
t1 = q1->in.type;
|
|
t2 = q2->in.type;
|
|
|
|
if( t1==ENUMTY || t2==ENUMTY )
|
|
{
|
|
/* check for enumerations */
|
|
if( logop( p->in.op ) && p->in.op != EQ && p->in.op != NE )
|
|
{
|
|
uerror( "illegal comparison of enums" );
|
|
return;
|
|
}
|
|
if( t1==ENUMTY && t2==ENUMTY && q1->fn.csiz==q2->fn.csiz )
|
|
return;
|
|
werror( "enumeration type clash, operator %s", opst[p->in.op] );
|
|
return;
|
|
}
|
|
|
|
if( ISPTR(t1) || ISARY(t1) )
|
|
{ /* switch roles: q1 should be non-pointer */
|
|
q1 = q2;
|
|
q2 = p->in.left;
|
|
}
|
|
|
|
if( !ISPTR(q1->in.type) && !ISARY(q1->in.type) )
|
|
{
|
|
if( q1->in.op == ICON && q1->tn.lval == 0 && q1->tn.rval == NONAME )
|
|
{ /* make the 0 have the type of the other side */
|
|
q1->fn.type = q2->fn.type;
|
|
q1->fn.cdim = q2->fn.cdim;
|
|
q1->fn.csiz = q2->fn.type;
|
|
}
|
|
else
|
|
{
|
|
combo( "pointer/integer", p );
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{ /* q1 and q2 still mean left and right */
|
|
d1 = q1->fn.cdim;
|
|
d2 = q2->fn.cdim;
|
|
for( ;; )
|
|
{
|
|
if( t1 == t2 )
|
|
{
|
|
;
|
|
if(q1->fn.csiz!=q2->fn.csiz)
|
|
{
|
|
combo( "structure pointer", p );
|
|
}
|
|
return;
|
|
}
|
|
if( ISARY(t1) || ISPTR(t1) )
|
|
{
|
|
if( !ISARY(t2) && !ISPTR(t2) ) break;
|
|
if( ISARY(t1) && ISARY(t2) &&
|
|
dimtab[d1] != dimtab[d2] )
|
|
{
|
|
combo( "array size", p );
|
|
return;
|
|
}
|
|
if( ISARY(t1) ) ++d1;
|
|
if( ISARY(t2) ) ++d2;
|
|
}
|
|
else break;
|
|
t1 = DECREF(t1);
|
|
t2 = DECREF(t2);
|
|
}
|
|
if ( BTYPE(t1) == VOID || BTYPE(t2) == VOID ) return;
|
|
combo( "pointer", p );
|
|
}
|
|
}
|
|
|
|
combo( s, p )
|
|
char *s;
|
|
NODE *p;
|
|
{
|
|
char buf[100];
|
|
sprintf( buf, "illegal %s combination, op %s", s, opst[p->tn.op] );
|
|
werror( buf );
|
|
}
|
|
|
|
NODE *
|
|
stref( p )
|
|
register NODE *p;
|
|
{
|
|
register TWORD t;
|
|
register d, s, dsc, align;
|
|
register OFFSZ off;
|
|
register struct symtab *q;
|
|
|
|
/* make p->x */
|
|
/* this is also used to reference automatic variables */
|
|
|
|
q = &stab[p->in.right->tn.rval];
|
|
p->in.right->in.op = FREE;
|
|
p->in.op = FREE;
|
|
p = pconvert( p->in.left );
|
|
|
|
/* make p look like ptr to x */
|
|
|
|
if( !ISPTR(p->in.type))
|
|
{
|
|
p->in.type = PTR+UNIONTY;
|
|
}
|
|
|
|
t = INCREF( q->stype );
|
|
d = q->dimoff;
|
|
s = q->sizoff;
|
|
|
|
p = makety( p, t, d, s );
|
|
|
|
/* compute the offset to be added */
|
|
|
|
off = q->offset;
|
|
dsc = q->sclass;
|
|
|
|
if( dsc & FIELD )
|
|
{
|
|
/* normalize offset */
|
|
switch(q->stype)
|
|
{
|
|
|
|
case CHAR:
|
|
case UCHAR:
|
|
align = ALCHAR;
|
|
s = CHAR;
|
|
break;
|
|
|
|
case SHORT:
|
|
case USHORT:
|
|
align = ALSHORT;
|
|
s = SHORT;
|
|
break;
|
|
|
|
case ENUMTY:
|
|
case INT:
|
|
case UNSIGNED:
|
|
align = ALINT;
|
|
s = INT;
|
|
break;
|
|
|
|
# ifdef LONGFIELDS
|
|
case LONG:
|
|
case ULONG:
|
|
align = ALLONG;
|
|
s = LONG;
|
|
break;
|
|
# endif
|
|
|
|
default:
|
|
cerror( "undefined bit field type" );
|
|
}
|
|
off = (off/align)*align;
|
|
}
|
|
if( off != 0 )
|
|
p = clocal( block( PLUS, p, offcon( off, t, d, s ), t, d, s ) );
|
|
|
|
p = buildtree( STAR, p, NIL );
|
|
|
|
/* if field, build field info */
|
|
|
|
if( dsc & FIELD )
|
|
{
|
|
p = block( FLD, p, NIL, q->stype, 0, q->sizoff );
|
|
p->tn.rval = PKFIELD(dsc&FLDSIZ,((int)(q->offset)%align)&077 );
|
|
}
|
|
|
|
return( clocal(p) );
|
|
}
|
|
|
|
notlval(p)
|
|
register NODE *p;
|
|
{
|
|
|
|
/* return 0 if p an lvalue, 1 otherwise */
|
|
|
|
again:
|
|
switch( p->in.op )
|
|
{
|
|
|
|
case FLD:
|
|
p = p->in.left;
|
|
goto again;
|
|
|
|
case STAR:
|
|
/* fix the &(a=b) bug, given that a and b are structures */
|
|
if( p->in.left->in.op == STASG ) return( 1 );
|
|
case NAME:
|
|
case VAUTO:
|
|
case VPARAM:
|
|
case RNODE:
|
|
case QNODE:
|
|
case SNODE:
|
|
if( ISARY(p->in.type) || ISFTN(p->in.type) ) return(1);
|
|
case REG:
|
|
return(0);
|
|
|
|
default:
|
|
return(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NODE *
|
|
bcon( i )
|
|
{
|
|
/* make a constant node with value i */
|
|
register NODE *p;
|
|
|
|
p = block( ICON, NIL, NIL, INT, 0, INT );
|
|
p->tn.lval = i;
|
|
p->tn.rval = NONAME;
|
|
return( clocal(p) );
|
|
}
|
|
|
|
NODE *
|
|
bpsize(p)
|
|
register NODE *p;
|
|
{
|
|
return( offcon( psize(p), p->in.type, p->fn.cdim, p->fn.csiz ) );
|
|
}
|
|
|
|
OFFSZ
|
|
psize( p )
|
|
register NODE *p;
|
|
{
|
|
/* p is a node of type pointer; psize returns the
|
|
** size of the thing pointed to
|
|
*/
|
|
|
|
if( !ISPTR(p->in.type) )
|
|
{
|
|
uerror( "pointer required");
|
|
return( SZINT );
|
|
}
|
|
/* note: no pointers to fields */
|
|
return( tsize( DECREF(p->in.type), p->fn.cdim, p->fn.csiz ) );
|
|
}
|
|
|
|
NODE *
|
|
unconvert( p, q )
|
|
register NODE *p, *q;
|
|
{
|
|
/* p is divided by the size of q */
|
|
/* q had better have type pointer */
|
|
|
|
# ifdef MYPDIV
|
|
return( clocal( block( PDIV, p, bpsize(q), INT, 0, INT ) ) );
|
|
# else
|
|
/* 10.4.
|
|
p = makety( p, PTRTYPE, 0, PTRTYPE );
|
|
p = clocal( buildtree( DIV, p, bpsize(q) ) );
|
|
|
|
return( makety( p, PTRTYPE, 0, PTRTYPE ) );
|
|
*/
|
|
p = makety( p, INT, 0, INT );
|
|
p = clocal( buildtree( DIV, p, bpsize(q) ) );
|
|
|
|
return( makety( p, INT, 0, INT ) );
|
|
# endif
|
|
}
|
|
|
|
NODE *
|
|
convert( p, f )
|
|
register NODE *p;
|
|
register f;
|
|
{
|
|
/* convert an operand of p
|
|
** f is either CVTL or CVTR
|
|
** operand has type int, and is converted by the size of the other side
|
|
*/
|
|
|
|
register NODE *q, *r;
|
|
|
|
if( f == CVTL )
|
|
{
|
|
q = p->in.left;
|
|
r = bpsize( p->in.right );
|
|
}
|
|
else
|
|
{
|
|
q = p->in.right;
|
|
r = bpsize( p->in.left );
|
|
}
|
|
# ifdef MYPMUL
|
|
r = clocal( block( PMUL, q, r, PTRTYPE, 0, PTRTYPE ) );
|
|
# else
|
|
/* if PTRTYPE is defined, make q this size; then, the MUL will be */
|
|
/*11.4.
|
|
q = makety( q, PTRTYPE, 0, PTRTYPE );
|
|
*/
|
|
q = makety( q, INT, 0, INT );
|
|
r = clocal( buildtree( MUL, q, r ) );
|
|
# endif
|
|
if( f == CVTL )
|
|
p->in.left = r;
|
|
else
|
|
p->in.right = r;
|
|
return(p);
|
|
|
|
}
|
|
|
|
econvert( p )
|
|
register NODE *p;
|
|
{
|
|
|
|
/* change enums to ints, or appropriate types */
|
|
|
|
register TWORD ty;
|
|
|
|
if( (ty=BTYPE(p->in.type)) == ENUMTY || ty == MOETY )
|
|
{
|
|
if( dimtab[ p->fn.csiz ] == SZCHAR ) ty = CHAR;
|
|
else if( dimtab[ p->fn.csiz ] == SZINT ) ty = INT;
|
|
else if( dimtab[ p->fn.csiz ] == SZSHORT ) ty = SHORT;
|
|
else ty = LONG;
|
|
ty = ctype( ty );
|
|
p->fn.csiz = ty;
|
|
MODTYPE(p->in.type,ty);
|
|
if( p->in.op == ICON && ty != LONG )
|
|
p->in.type = p->fn.csiz = INT;
|
|
}
|
|
}
|
|
|
|
NODE *
|
|
pconvert( p )
|
|
register NODE *p;
|
|
{
|
|
register TWORD t;
|
|
|
|
/* if p should be changed into a pointer, do so */
|
|
/* also, widen p so it can be used as an operand */
|
|
|
|
if( ISARY( p->in.type) )
|
|
{
|
|
p->in.type = DECREF( p->in.type );
|
|
++p->fn.cdim;
|
|
return( buildtree( UNARY AND, p, NIL ) );
|
|
}
|
|
if( ISFTN( p->in.type) )
|
|
return( buildtree( UNARY AND, p, NIL ) );
|
|
|
|
t = indtype( p->tn.type );
|
|
if( t == p->tn.type ) return( p );
|
|
if( p->tn.op == CONV && cbigger( p ) )
|
|
{
|
|
p->tn.type = p->fn.csiz = t;
|
|
}
|
|
else p = makety( p, t, 0, (int) t );
|
|
return( p );
|
|
}
|
|
|
|
bigsize( t )
|
|
TWORD t;
|
|
{
|
|
/* return a type size for t */
|
|
switch( t )
|
|
{
|
|
|
|
case CHAR:
|
|
case UCHAR:
|
|
return( SZCHAR );
|
|
|
|
case SHORT:
|
|
case USHORT:
|
|
return( SZSHORT );
|
|
|
|
case VOID:
|
|
case INT:
|
|
case UNSIGNED:
|
|
return( SZINT );
|
|
|
|
case LONG:
|
|
case ULONG:
|
|
return( SZLONG );
|
|
|
|
case FLOAT:
|
|
return( SZLONG+1 ); /* must appear > long */
|
|
case DOUBLE:
|
|
return( SZLONG+2 );
|
|
|
|
}
|
|
|
|
if( ISPTR(t) || ISARY(t) ) return( SZPOINT );
|
|
cerror( "bad bigsize: 0%o", t );
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
cbigger( p )
|
|
register NODE *p;
|
|
{
|
|
/* returns 1 if the conversion op p makes things bigger */
|
|
|
|
if( p->tn.op != CONV ) cerror( "cbigger" );
|
|
return( bigsize( p->tn.type ) > bigsize( p->in.left->tn.type ) );
|
|
}
|
|
|
|
NODE *
|
|
oconvert(p)
|
|
register NODE *p;
|
|
|
|
{
|
|
/* convert the result itself: used for pointer and unsigned */
|
|
register TWORD t;
|
|
|
|
switch(p->in.op)
|
|
{
|
|
|
|
case LE:
|
|
case LT:
|
|
case GE:
|
|
case GT:
|
|
t = p->in.left->in.type;
|
|
if( ISUNSIGNED(t) || ISPTR(t) || ISARY(t) )
|
|
{
|
|
p->in.op += (ULE-LE);
|
|
}
|
|
else
|
|
{
|
|
t = p->in.right->in.type;
|
|
if( ISUNSIGNED(t) || ISPTR(t) || ISARY(t) )
|
|
{
|
|
p->in.op += (ULE-LE);
|
|
}
|
|
}
|
|
case EQ:
|
|
case NE:
|
|
case ULE:
|
|
case ULT:
|
|
case UGE:
|
|
case UGT:
|
|
return( p );
|
|
|
|
case MINUS:
|
|
return( unconvert( p, p->in.left ) );
|
|
}
|
|
|
|
cerror( "illegal oconvert: %d", p->in.op );
|
|
|
|
return(p);
|
|
}
|
|
|
|
NODE *
|
|
ptmatch(p)
|
|
register NODE *p;
|
|
{
|
|
|
|
/* makes the operands of p agree; they are
|
|
** either pointers or integers, by this time
|
|
*/
|
|
/* with MINUS, the sizes must be the same */
|
|
/* with COLON, the types must be the same */
|
|
|
|
register TWORD t1, t2, t;
|
|
register o, d2, d, s2, s;
|
|
|
|
o = p->in.op;
|
|
t = t1 = p->in.left->in.type;
|
|
t2 = p->in.right->in.type;
|
|
d = p->in.left->fn.cdim;
|
|
d2 = p->in.right->fn.cdim;
|
|
s = p->in.left->fn.csiz;
|
|
s2 = p->in.right->fn.csiz;
|
|
|
|
switch( o )
|
|
{
|
|
|
|
case ASSIGN:
|
|
case RETURN:
|
|
case CAST:
|
|
break;
|
|
|
|
case MINUS:
|
|
if( psize(p->in.left) != psize(p->in.right) )
|
|
{
|
|
uerror( "illegal pointer subtraction");
|
|
}
|
|
/* 10.4. p->tn.type = p->fn.csiz = PTRTYPE;
|
|
*/
|
|
p->tn.type = p->fn.csiz = INT;
|
|
p->fn.cdim = 0;
|
|
return( clocal(p) );
|
|
|
|
case COLON:
|
|
if(t1 == t2)
|
|
break;
|
|
if(ISPTR(t1) && ISPTR(t2) &&
|
|
(BTYPE(t1)==VOID || BTYPE(t2)==VOID))
|
|
break;
|
|
else
|
|
uerror( "illegal types in :");
|
|
break;
|
|
|
|
default:
|
|
if( !ISPTR(t1) )
|
|
{
|
|
t = t2;
|
|
d = d2;
|
|
s = s2;
|
|
break;
|
|
}
|
|
if( !ISPTR(t2) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* both are pointers */
|
|
if( talign(t2,s2) < talign(t,s) )
|
|
{
|
|
t = t2;
|
|
s = s2;
|
|
}
|
|
break;
|
|
}
|
|
|
|
p->in.left = makety( p->in.left, t, d, s );
|
|
p->in.right = makety( p->in.right, t, d, s );
|
|
if( !logop(o) )
|
|
{
|
|
p->in.type = t;
|
|
p->fn.cdim = d;
|
|
p->fn.csiz = s;
|
|
}
|
|
|
|
return(clocal(p));
|
|
}
|
|
|
|
int tdebug = 0;
|
|
|
|
NODE *
|
|
tymatch(p)
|
|
register NODE *p;
|
|
{
|
|
|
|
/* satisfy the types of various arithmetic binary ops */
|
|
|
|
/* rules are:
|
|
** if any float or doubles, make double
|
|
** if any longs, make long
|
|
** if any ints, make int
|
|
** if any shorts, make short
|
|
** otherwise, make char
|
|
** if either operand is unsigned, the result is...
|
|
** if a simple assignment, type = type of lhs
|
|
** if an asg. op, type = type of original lhs
|
|
** (under CONV, if any)
|
|
*/
|
|
|
|
register o;
|
|
register TWORD t1, t2;
|
|
TWORD t, tu;
|
|
register NODE *l, *r;
|
|
int u;
|
|
|
|
o = p->in.op;
|
|
|
|
convasgflg = 0;
|
|
orgtleft = t1 = (l=p->in.left)->in.type;
|
|
t2 = (r=p->in.right)->in.type;
|
|
|
|
/* constants have a kind of "flexible" type */
|
|
|
|
if( r->tn.op == ICON && r->tn.rval == NONAME &&
|
|
(t1==CHAR || t1==UCHAR || t1==SHORT || t1==USHORT) )
|
|
{
|
|
/* if the constant retains its value when cast to the
|
|
** type of the lhs, assume it has the lhs type
|
|
*/
|
|
if( r->tn.lval == ccast( r->tn.lval, t1 ) )
|
|
{
|
|
r->in.type = t2 = t1;
|
|
r->fn.cdim = l->fn.cdim;
|
|
r->fn.csiz = l->fn.csiz;
|
|
}
|
|
}
|
|
|
|
/* this is the opposite case from the above (it is too early
|
|
to assume that constants are on the right) */
|
|
|
|
if( l->tn.op == ICON && l->tn.rval == NONAME &&
|
|
(t2==CHAR || t2==UCHAR || t2==SHORT || t2==USHORT) )
|
|
{
|
|
/* if the constant retains its value when cast to the
|
|
** type of the rhs, assume it has the rhs type
|
|
*/
|
|
if( l->tn.lval == ccast( l->tn.lval, t2 ) )
|
|
{
|
|
l->in.type = t1 = t2;
|
|
l->fn.cdim = r->fn.cdim;
|
|
l->fn.csiz = r->fn.csiz;
|
|
}
|
|
}
|
|
if( (t1==VOID || t2==VOID) && o!=CAST )
|
|
uerror("void type illegal in expression");
|
|
|
|
u = 0;
|
|
if( ISUNSIGNED(t1) )
|
|
{
|
|
u = 1;
|
|
t1 = DEUNSIGN(t1);
|
|
}
|
|
if( ISUNSIGNED(t2) )
|
|
{
|
|
u = 1;
|
|
t2 = DEUNSIGN(t2);
|
|
}
|
|
|
|
if( t1==DOUBLE || t1==FLOAT || t2==DOUBLE || t2==FLOAT ) t = DOUBLE;
|
|
else if( t1==LONG || t2==LONG ) t = LONG;
|
|
else if( t1==INT || t2==INT ) t = INT;
|
|
else if( t1==SHORT || t2==SHORT ) t = SHORT;
|
|
else t = CHAR;
|
|
|
|
if( o == ASSIGN || o == CAST || o == RETURN )
|
|
{
|
|
tu = t1;
|
|
if( o == RETURN )
|
|
{
|
|
if( tu==FLOAT ) tu = DOUBLE;
|
|
else if( tu==CHAR || tu==SHORT ) tu = INT;
|
|
}
|
|
t = t1 = tu; /* t1 set to avoid lhs conversion */
|
|
if( ISUNSIGNED(l->tn.type) ) u=1;
|
|
else u=0;
|
|
t2 = r->tn.type; /* back to reality... */
|
|
}
|
|
tu = (u && UNSIGNABLE(t))?ENUNSIGN(t):t;
|
|
|
|
if( tu != t1 ) p->in.left = makety( l, tu, 0, (int)tu );
|
|
if( tu != t2 ) p->in.right = makety( r, tu, 0, (int)tu );
|
|
|
|
if( !logop(o) ) /* the type of the node = type of the operation */
|
|
{
|
|
p->in.type = tu;
|
|
p->fn.cdim = 0;
|
|
p->fn.csiz = t;
|
|
}
|
|
|
|
if( asgop(o) && p->in.left->tn.op == CONV )
|
|
{
|
|
/* original, unconverted type */
|
|
/* this will get rewritten to A = A op B, in most cases */
|
|
/* if the op is an unsigned op, change the lhs to unsigned */
|
|
convasgflg = 1;
|
|
l = p->in.left->in.left;
|
|
tu = l->in.type;
|
|
if( u && (UNSIGNABLE(tu)) ) tu = ENUNSIGN(tu);
|
|
p->in.type = l->in.type = tu;
|
|
p->fn.cdim = l->fn.cdim;
|
|
p->fn.csiz = l->fn.csiz;
|
|
}
|
|
|
|
# ifndef NODBG
|
|
if( tdebug )
|
|
{
|
|
printf( "tymatch(%lx): %x '%s' %x => %x\n",p,t1,opst[o],t2,tu );
|
|
e2print(p);
|
|
}
|
|
# endif
|
|
|
|
return(p);
|
|
}
|
|
|
|
NODE *
|
|
makety( p, t, d, s )
|
|
register NODE *p;
|
|
register TWORD t;
|
|
register d,s;
|
|
{
|
|
/* make p into type t by inserting a conversion */
|
|
register TWORD pt;
|
|
|
|
pt = p->in.type;
|
|
|
|
if( pt == ENUMTY && p->in.op == ICON )
|
|
{
|
|
econvert(p);
|
|
pt = p->in.type;
|
|
}
|
|
if( t == pt )
|
|
{
|
|
rew:
|
|
p->fn.type = t;
|
|
p->fn.cdim = d;
|
|
p->fn.csiz = s;
|
|
|
|
/* for really heavy debugging
|
|
printf( "block( %s, %d, %d, 0%o, %d, %d ) yields %d\n",
|
|
opst[o], l-node, r-node, t, d, s, p-node );
|
|
*/
|
|
|
|
return( p );
|
|
}
|
|
|
|
if( t & TMASK )
|
|
{
|
|
/* non-simple type */
|
|
if( ISPTR(pt)
|
|
# ifdef TWOPTRS
|
|
&& TWOPTRS(t) == TWOPTRS(pt)
|
|
# endif
|
|
)
|
|
{
|
|
/* don't generate CONV: just rewrite type */
|
|
goto rew;
|
|
}
|
|
|
|
return( block( CONV, p, NIL, t, d, s ) );
|
|
}
|
|
|
|
if( p->in.op == ICON && p->tn.rval==NONAME )
|
|
{
|
|
if( t==DOUBLE||t==FLOAT )
|
|
{
|
|
p->in.op = FCON;
|
|
if( ISUNSIGNED(pt) )
|
|
{
|
|
p->fpn.dval = /* (unsigned CONSZ) */ p->tn.lval;
|
|
}
|
|
else
|
|
{
|
|
p->fpn.dval = p->tn.lval;
|
|
}
|
|
goto rew;
|
|
}
|
|
p->tn.lval = ccast( p->tn.lval, t );
|
|
goto rew;
|
|
}
|
|
return( block( CONV, p, NIL, t, d, s ) );
|
|
}
|
|
|
|
NODE *
|
|
block( o, l, r, t, d, s )
|
|
register NODE *l, *r;
|
|
register TWORD t;
|
|
register o,d,s;
|
|
{
|
|
|
|
register NODE *p;
|
|
|
|
p = talloc();
|
|
p->in.op = o;
|
|
p->in.left = l;
|
|
p->in.right = r;
|
|
p->in.type = t;
|
|
p->fn.cdim = d;
|
|
p->fn.csiz = s;
|
|
return(p);
|
|
}
|
|
|
|
icons(p)
|
|
register NODE *p;
|
|
{
|
|
/* if p is an integer constant, return its value */
|
|
register val;
|
|
|
|
if( p->in.op != ICON )
|
|
{
|
|
uerror( "constant expected");
|
|
val = 1;
|
|
}
|
|
else
|
|
{
|
|
val = p->tn.lval;
|
|
if( val != p->tn.lval )
|
|
/*
|
|
if((p->tn.lval & 0xffff0000) &&
|
|
(p->tn.lval & 0xffff0000) != 0xffff0000)
|
|
*/
|
|
uerror( "warning: constant too big for compiler" );
|
|
}
|
|
tfree( p );
|
|
return(val);
|
|
}
|
|
|
|
/* the intent of this table is to examine the
|
|
** operators, and to check them for
|
|
** correctness.
|
|
**
|
|
** The table is searched for the op and the
|
|
** modified type (where this is one of the
|
|
** types INT (includes char and short), LONG,
|
|
** DOUBLE (includes FLOAT), and POINTER
|
|
**
|
|
** The default action is to make the node type integer
|
|
**
|
|
** The actions taken include:
|
|
** PUN check for puns
|
|
** CVTL convert the left operand
|
|
** CVTR convert the right operand
|
|
** TYPL the type is determined by the left operand
|
|
** TYPR the type is determined by the right operand
|
|
** TYMATCH force type of left and right to match, by inserting conversions
|
|
** PTMATCH like TYMATCH, but for pointers
|
|
** LVAL left operand must be lval
|
|
** CVTO convert the op
|
|
** NCVT do not convert the operands
|
|
** OTHER handled by code
|
|
** NCVTR convert the left operand, not the right...
|
|
**
|
|
*/
|
|
|
|
# define MINT 01 /* integer */
|
|
# define MDBI 02 /* integer or double */
|
|
# define MSTR 04 /* structure */
|
|
# define MPTR 010 /* pointer */
|
|
# define MPTI 020 /* pointer or integer */
|
|
# define MENU 040 /* enumeration variable or member */
|
|
|
|
opact( p )
|
|
register NODE *p;
|
|
{
|
|
register mt12, mt1, mt2, o;
|
|
|
|
mt12 = 0;
|
|
|
|
switch( optype(o=p->in.op) )
|
|
{
|
|
|
|
case BITYPE:
|
|
mt12=mt2 = moditype( p->in.right->in.type );
|
|
case UTYPE:
|
|
mt12 &= (mt1 = moditype( p->in.left->in.type ));
|
|
|
|
}
|
|
|
|
switch( o )
|
|
{
|
|
|
|
case NAME :
|
|
case STRING :
|
|
case ICON :
|
|
case FCON :
|
|
case CALL :
|
|
case UNARY CALL:
|
|
case STAR:
|
|
{
|
|
return( OTHER );
|
|
}
|
|
case UNARY MINUS:
|
|
if( mt1 & MDBI ) return( TYPL );
|
|
break;
|
|
|
|
case COMPL:
|
|
if( mt1 & MINT ) return( TYPL );
|
|
break;
|
|
|
|
case UNARY AND:
|
|
{
|
|
return( NCVT+OTHER );
|
|
}
|
|
case INIT:
|
|
case CM:
|
|
return( 0 );
|
|
case NOT:
|
|
case CBRANCH:
|
|
case ANDAND:
|
|
case OROR:
|
|
return( NCVT );
|
|
|
|
case MUL:
|
|
case DIV:
|
|
if( mt12 & MDBI ) return( TYMATCH );
|
|
break;
|
|
|
|
case MOD:
|
|
case AND:
|
|
case OR:
|
|
case ER:
|
|
case LS:
|
|
case RS:
|
|
if( mt12 & MINT ) return( TYMATCH );
|
|
break;
|
|
|
|
case EQ:
|
|
case NE:
|
|
case LT:
|
|
case LE:
|
|
case GT:
|
|
case GE:
|
|
if( (mt1&MENU)||(mt2&MENU) ) return( PTMATCH+PUN+NCVT );
|
|
if( mt12 & MDBI ) return( TYMATCH+CVTO+NCVT );
|
|
else if( mt12 & MPTR ) return( PTMATCH+PUN+CVTO );
|
|
else if( mt12 & MPTI ) return( PTMATCH+PUN+CVTO );
|
|
else break;
|
|
|
|
case QUEST:
|
|
case COMOP:
|
|
return( TYPR+NCVTR );
|
|
|
|
case STREF:
|
|
return( NCVTR+OTHER );
|
|
|
|
case COLON:
|
|
if( mt12 & MENU ) return( NCVT+PUN+PTMATCH );
|
|
else if( mt12 & MDBI ) return( TYMATCH );
|
|
else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN );
|
|
else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN );
|
|
else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN );
|
|
else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER );
|
|
break;
|
|
|
|
case ASSIGN:
|
|
case RETURN:
|
|
if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER );
|
|
case CAST:
|
|
if(o==CAST && mt1==0)return(TYPL+TYMATCH);
|
|
if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH );
|
|
else if( (mt1&MENU)||(mt2&MENU) )
|
|
{
|
|
return( LVAL+NCVT+TYPL+PTMATCH+PUN );
|
|
}
|
|
else if( mt12 == 0 ) break;
|
|
else if( mt1 & MPTR ) return( LVAL+PTMATCH+PUN );
|
|
else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN );
|
|
break;
|
|
|
|
case ASG MUL:
|
|
case ASG DIV:
|
|
if( mt12 & MDBI ) return( LVAL+TYMATCH );
|
|
break;
|
|
|
|
case ASG MOD:
|
|
case ASG AND:
|
|
case ASG OR:
|
|
case ASG ER:
|
|
case ASG LS:
|
|
case ASG RS:
|
|
if( mt12 & MINT ) return( LVAL+TYMATCH );
|
|
break;
|
|
|
|
case ASG PLUS:
|
|
case ASG MINUS:
|
|
case INCR:
|
|
case DECR:
|
|
if( mt12 & MDBI ) return( TYMATCH+LVAL );
|
|
else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+LVAL+CVTR );
|
|
break;
|
|
|
|
case MINUS:
|
|
if( mt12 & MPTR ) return( CVTO+PTMATCH+PUN );
|
|
if( mt2 & MPTR ) break;
|
|
case PLUS:
|
|
if( mt12 & MDBI ) return( TYMATCH );
|
|
else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+CVTR );
|
|
else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+CVTL );
|
|
|
|
/* special operators */
|
|
case UOP0:
|
|
case UOP1:
|
|
case UOP2:
|
|
case UOP3:
|
|
case UOP4:
|
|
case UOP5:
|
|
case UOP6:
|
|
case UOP7:
|
|
case UOP8:
|
|
case UOP9:
|
|
return( TYPL );
|
|
}
|
|
lerror( "operands of %s have incompatible types", opst[o] );
|
|
return( NCVT );
|
|
}
|
|
|
|
moditype( ty )
|
|
register TWORD ty;
|
|
{
|
|
|
|
switch( ty )
|
|
{
|
|
|
|
case UNDEF:
|
|
case VOID:
|
|
return(0); /* type is void */
|
|
case ENUMTY:
|
|
case MOETY:
|
|
return( MENU );
|
|
|
|
case STRTY:
|
|
case UNIONTY:
|
|
return( MSTR );
|
|
|
|
case CHAR:
|
|
case SHORT:
|
|
case UCHAR:
|
|
case USHORT:
|
|
return( MINT|MPTI|MDBI );
|
|
|
|
case UNSIGNED:
|
|
case ULONG:
|
|
case INT:
|
|
case LONG:
|
|
return( MINT|MDBI|MPTI );
|
|
|
|
case FLOAT:
|
|
case DOUBLE:
|
|
return( MDBI );
|
|
|
|
default:
|
|
return( MPTR|MPTI );
|
|
}
|
|
}
|
|
|
|
# ifndef MYCCAST
|
|
CONSZ
|
|
ccast( v, t )
|
|
register CONSZ v;
|
|
register TWORD t;
|
|
{
|
|
/* cast value v into simple type t */
|
|
/* must be done as it would be on the target machine */
|
|
|
|
switch( t )
|
|
{
|
|
|
|
case CHAR:
|
|
# ifdef CHSIGN
|
|
if( v&ONEBIT(SZCHAR-1) )
|
|
{
|
|
return( v | ~BITMASK(SZCHAR) );
|
|
}
|
|
# endif
|
|
case UCHAR:
|
|
return( v & BITMASK(SZCHAR) );
|
|
|
|
case SHORT:
|
|
if( v&ONEBIT(SZSHORT-1) )
|
|
{
|
|
return( v | ~BITMASK(SZSHORT) );
|
|
}
|
|
case USHORT:
|
|
return( v & BITMASK(SZSHORT) );
|
|
|
|
case INT:
|
|
if( v&ONEBIT(SZINT-1) )
|
|
{
|
|
return( v | ~BITMASK(SZINT) );
|
|
}
|
|
case UNSIGNED:
|
|
return( v & BITMASK(SZINT) );
|
|
|
|
default:
|
|
return( v );
|
|
}
|
|
}
|
|
# endif
|
|
|
|
|
|
NODE *
|
|
doszof( p )
|
|
register NODE *p;
|
|
{
|
|
/* do sizeof p */
|
|
register i;
|
|
|
|
/* whatever is the meaning of this if it is a bitfield? */
|
|
i = tsize( p->in.type, p->fn.cdim, p->fn.csiz )/SZCHAR;
|
|
|
|
tfree(p);
|
|
if( i <= 0 ) werror( "sizeof returns 0" );
|
|
p = bcon(i);
|
|
p->tn.type = UNSIGNED; /* damn dmr anyhow! */
|
|
return( p );
|
|
}
|
|
|
|
# ifndef NODBG
|
|
eprint(p)
|
|
NODE *p;
|
|
{
|
|
printf("\n++++++++\n");
|
|
e1print(p,"T");
|
|
printf("---------\n");
|
|
}
|
|
e1print( p ,s)
|
|
register NODE *p;
|
|
char *s;
|
|
{
|
|
register ty, d;
|
|
static down = 0;
|
|
|
|
ty = optype( p->tn.op );
|
|
|
|
if( ty == BITYPE )
|
|
{
|
|
++down;
|
|
e1print( p->in.right ,"R");
|
|
--down;
|
|
}
|
|
|
|
for( d=down; d>1; d -= 2 ) printf( "\t" );
|
|
if( d ) printf( " " );
|
|
|
|
printf("%s=%d) %s, ", s, (int) (p-node), opst[p->in.op] );
|
|
if( ty == LTYPE )
|
|
{
|
|
printf( "lval=%ld", p->tn.lval );
|
|
printf( ", rval=%d, ", p->tn.rval );
|
|
}
|
|
printf("type=");
|
|
tprint( p->in.type );
|
|
printf( ", dim=%d, siz=%d\n", p->fn.cdim, p->fn.csiz );
|
|
if( ty != LTYPE )
|
|
{
|
|
++down;
|
|
e1print( p->in.left ,"L");
|
|
--down;
|
|
}
|
|
}
|
|
|
|
tprint( t )
|
|
register TWORD t;
|
|
{
|
|
/* output a nice description of the type of t */
|
|
static char * tnames[] =
|
|
{
|
|
"undef",
|
|
"farg",
|
|
"char",
|
|
"short",
|
|
"int",
|
|
"long",
|
|
"float",
|
|
"double",
|
|
"strty",
|
|
"unionty",
|
|
"enumty",
|
|
"moety",
|
|
"uchar",
|
|
"ushort",
|
|
"unsigned",
|
|
"ulong",
|
|
"?", "?"
|
|
};
|
|
|
|
for(;; t = DECREF(t) )
|
|
{
|
|
if( ISPTR(t) ) printf( "PTR " );
|
|
else if( ISFTN(t) ) printf( "FTN " );
|
|
else if( ISARY(t) ) printf( "ARY " );
|
|
else
|
|
{
|
|
printf( "%s", tnames[BTYPE(t)] );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
|
|
# ifndef MYLOCCTR
|
|
locctr(l)
|
|
register l;
|
|
{
|
|
register temp, lt;
|
|
/* look in locnames; print out the location counter name */
|
|
/* null means use the next; all null, don't print */
|
|
for( lt=l; lt<=STRNG && !locnames[lt]; ++lt )
|
|
{
|
|
/* EMPTY */
|
|
}
|
|
if( lt == curloc ) return( lt );
|
|
temp = curloc;
|
|
if( lt > STRNG ) lt = l;
|
|
/*
|
|
else printf( locnames[lt] );
|
|
Fuer variable Segmentnamen bei Daten geaendert !!!!!!!
|
|
*/
|
|
else
|
|
printf(locnames[lt], datanm);
|
|
curloc = lt;
|
|
return( temp );
|
|
}
|
|
# endif
|
|
|
|
# ifndef NOFLOAT
|
|
|
|
prtdcon( p )
|
|
register NODE *p;
|
|
{
|
|
register i;
|
|
register TWORD t;
|
|
register NODE *hp;
|
|
|
|
if( p->in.op == CBRANCH && optype((hp=p->in.left)->in.op) == BITYPE ) {
|
|
if( hp->in.right->in.op==FCON && hp->in.right->fpn.dval==0 ) {
|
|
hp->in.right->in.op = FREE;
|
|
hp->in.right = bcon(0);
|
|
}
|
|
else
|
|
if( hp->in.left->in.op==FCON && hp->in.left->fpn.dval==0 ) {
|
|
hp->in.left->in.op = FREE;
|
|
hp->in.left = bcon(0);
|
|
}
|
|
}
|
|
if( p->in.op == FCON )
|
|
{
|
|
locctr( DATA );
|
|
t = p->tn.type;
|
|
defalign( t==DOUBLE?ALDOUBLE:ALFLOAT );
|
|
deflab( i = getlab() );
|
|
fincode( p->fpn.dval, t==DOUBLE?SZDOUBLE:SZFLOAT );
|
|
p->tn.lval = 0;
|
|
p->tn.rval = -i;
|
|
p->in.op = NAME;
|
|
}
|
|
if( (i = optype(p->in.op)) == BITYPE ) prtdcon( p->in.right );
|
|
if( i != LTYPE ) prtdcon( p->in.left );
|
|
}
|
|
# endif
|
|
|
|
# ifndef MYLABELS
|
|
getlab()
|
|
{
|
|
static crslab = 10;
|
|
return( ++crslab );
|
|
}
|
|
# endif
|
|
|
|
int edebug = 0;
|
|
ecomp( p )
|
|
register NODE *p;
|
|
{
|
|
# ifndef NODBG
|
|
if( edebug ) eprint(p);
|
|
# endif
|
|
if( !reached )
|
|
{
|
|
werror( "statement not reached" );
|
|
reached = 1;
|
|
}
|
|
# ifdef CLOCAL
|
|
p = clocal(p);
|
|
# endif
|
|
p = optim(p);
|
|
# ifndef NOFLOAT
|
|
prtdcon(p);
|
|
# endif
|
|
locctr( PROG );
|
|
ecode(p);
|
|
tfree(p);
|
|
}
|
|
|
|
# ifndef MYECODE
|
|
ecode( p )
|
|
register NODE *p;
|
|
{
|
|
/* standard version of writing the tree nodes */
|
|
if( nerrors ) return;
|
|
# ifdef SDB
|
|
sdbline();
|
|
# endif
|
|
|
|
p2tree( p );
|
|
p2compile( p );
|
|
}
|
|
# endif
|
|
|
|
# ifdef STDPRTREE /****************************************/
|
|
|
|
# ifndef RNODNAME
|
|
# define RNODNAME LABFMT
|
|
# endif
|
|
|
|
# ifndef ONEPASS
|
|
|
|
prtree(p) register NODE *p; {
|
|
|
|
register struct symtab *q;
|
|
register ty;
|
|
|
|
# ifdef MYPRTREE
|
|
MYPRTREE(p); /* local action can be taken here; then return... */
|
|
#endif
|
|
|
|
ty = optype(p->in.op);
|
|
|
|
printf( "%d\t", p->in.op );
|
|
|
|
if( ty == LTYPE ) {
|
|
printf( CONFMT, p->tn.lval );
|
|
printf( "\t" );
|
|
}
|
|
if( ty != BITYPE ) {
|
|
if( p->in.op == NAME || p->in.op == ICON ) printf( "0\t" );
|
|
else printf( "%d\t", p->tn.rval );
|
|
}
|
|
|
|
printf( "%o\t", p->in.type );
|
|
|
|
/* handle special cases */
|
|
|
|
switch( p->in.op ){
|
|
|
|
case NAME:
|
|
case ICON:
|
|
/* print external name */
|
|
if( p->tn.rval == NONAME ) printf( "\n" );
|
|
else if( p->tn.rval >= 0 ){
|
|
q = &stab[p->tn.rval];
|
|
printf( "%.8s\n", exname(q->sname) );
|
|
}
|
|
else { /* label */
|
|
printf( LABFMT, -p->tn.rval );
|
|
printf("\n");
|
|
}
|
|
break;
|
|
|
|
case STARG:
|
|
case STASG:
|
|
case STCALL:
|
|
case UNARY STCALL:
|
|
/* print out size */
|
|
/* use lhs size, in order to avoid hassles with the structure `.' operator */
|
|
|
|
/* note: p->in.left not a field... */
|
|
printf( CONFMT, (CONSZ) tsize( STRTY, p->in.left->fn.cdim, p->in.left->fn.csiz ) );
|
|
printf( "\t%d\t\n", talign( STRTY, p->in.left->fn.csiz ) );
|
|
break;
|
|
|
|
default:
|
|
printf( "\n" );
|
|
}
|
|
|
|
if( ty != LTYPE ) prtree( p->in.left );
|
|
if( ty == BITYPE ) prtree( p->in.right );
|
|
|
|
}
|
|
|
|
# endif not defined ONEPASS
|
|
|
|
p2tree(p)
|
|
register NODE *p;
|
|
{
|
|
register ty;
|
|
register NODE *l;
|
|
register o;
|
|
char temp[32]; /* place to dump label stuff */
|
|
|
|
# ifdef MYP2TREE
|
|
MYP2TREE(p); /* local action can be taken here; then return... */
|
|
# endif
|
|
|
|
/* this routine sits painfully between pass1 and pass2 */
|
|
ty = optype(o=p->in.op);
|
|
p->tn.goal = 0; /* an illegal goal, just to clear it out */
|
|
p->tn.type = ttype( p->tn.type ); /* type gets second-pass (bits) */
|
|
switch( o )
|
|
{
|
|
|
|
case TEMP:
|
|
case NAME:
|
|
case ICON:
|
|
case VAUTO:
|
|
case VPARAM:
|
|
if( p->tn.rval == NONAME )
|
|
p->in.name = (char *) 0;
|
|
else if( p->tn.rval >= 0 )
|
|
{
|
|
/* copy name from exname */
|
|
register char *cp;
|
|
cp = exname( stab[p->tn.rval].sname );
|
|
p->in.name = tstr( cp );
|
|
}
|
|
else if( p->tn.rval == - strftn )
|
|
{
|
|
sprintf( temp, RNODNAME, -p->tn.rval );
|
|
p->in.name = tstr( temp );
|
|
}
|
|
else
|
|
{
|
|
sprintf( temp, LABFMT, -p->tn.rval );
|
|
p->in.name = tstr( temp );
|
|
}
|
|
break;
|
|
|
|
case STARG:
|
|
case STASG:
|
|
case STCALL:
|
|
case UNARY STCALL:
|
|
/* set up size parameters */
|
|
l = p->in.left;
|
|
p->stn.stsize = tsize(STRTY,l->fn.cdim,l->fn.csiz);
|
|
p->stn.stalign = talign(STRTY,l->fn.csiz);
|
|
break;
|
|
/* this should do something only if temporary regs are
|
|
/* built into the tree by machine-dependent actions */
|
|
case REG:
|
|
rbusy( p->tn.rval, p->in.type );
|
|
default:
|
|
p->in.name = (char *) 0;
|
|
}
|
|
|
|
if( ty != LTYPE ) p2tree( p->in.left );
|
|
if( ty == BITYPE ) p2tree( p->in.right );
|
|
}
|
|
|
|
# endif /******************************************/
|