static char *sccsid
="@(#)trees.c 4.30 (Berkeley) %G%";
/* corrections when in violation of lint */
/* some special actions, used in finding the type of nodes */
register struct actions
*p
;
for (p
= actions
; p
->a_name
; p
++)
printf("%s%s", sep
, p
->a_name
);
NAME: rval>0 is stab index for external
rval<0 is -inlabel number
rval has the STAB index, or - label number,
if a name whose address is in the constant
rval = NONAME means no name
REG: rval is reg. identification cookie
buildtree( o
, l
, r
) register NODE
*l
, *r
; {
register struct symtab
*sp
;
if( bdebug
) printf( "buildtree( %s, %o, %o )\n", opst
[o
], l
, r
);
/* check for constants */
if( opty
== UTYPE
&& l
->in
.op
== ICON
){
if( hflag
) werror( "constant argument to NOT" );
if( conval( l
, o
, l
) ) return(l
);
else if( o
==UNARY MINUS
&& l
->in
.op
==FCON
){
l
->fpn
.fval
= -l
->fpn
.fval
;
else if( o
==UNARY MINUS
&& l
->in
.op
==DCON
){
l
->dpn
.dval
= -l
->dpn
.dval
;
else if( o
==QUEST
&& l
->in
.op
==ICON
) {
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
){
if( l
->in
.type
== ENUMTY
&& r
->in
.type
== ENUMTY
){
p
= block( o
, l
, r
, INT
, 0, INT
);
if( hflag
) werror( "constant in conditional context" );
if( conval( l
, o
, r
) ) {
else if (opty
== BITYPE
&&
(l
->in
.op
== FCON
|| l
->in
.op
== DCON
|| l
->in
.op
== ICON
) &&
(r
->in
.op
== FCON
|| r
->in
.op
== DCON
|| r
->in
.op
== ICON
)) {
if (o
== PLUS
|| o
== MINUS
|| o
== MUL
|| o
== DIV
) {
l
->dpn
.dval
= l
->tn
.lval
;
else if (l
->in
.op
== FCON
)
l
->dpn
.dval
= l
->fpn
.fval
;
r
->dpn
.dval
= r
->tn
.lval
;
else if (r
->in
.op
== FCON
)
r
->dpn
.dval
= r
->fpn
.fval
;
l
->dpn
.dval
+= r
->dpn
.dval
;
l
->dpn
.dval
-= r
->dpn
.dval
;
l
->dpn
.dval
*= r
->dpn
.dval
;
uerror("division by 0.");
l
->dpn
.dval
/= r
->dpn
.dval
;
uerror("floating point exception in constant expression");
l
->dpn
.dval
= 1.0; /* Fairly harmless */
l
->in
.type
= l
->fn
.csiz
= DOUBLE
;
/* it's real; we must make a new node */
p
= block( o
, l
, r
, INT
, 0, INT
);
if( actions
&LVAL
){ /* check left descendent */
if( notlval(p
->in
.left
) ) {
uerror( "illegal lvalue operand of assignment operator" );
p
->in
.left
= pconvert( p
->in
.left
);
else if( !(actions
& NCVT
) ){
p
->in
.right
= pconvert( p
->in
.right
);
p
->in
.left
= pconvert( p
->in
.left
);
if( (actions
&PUN
) && (o
!=CAST
||cflag
) ){
if( actions
& (TYPL
|TYPR
) ){
q
= (actions
&TYPL
) ? p
->in
.left
: p
->in
.right
;
if( actions
& CVTL
) p
= convert( p
, CVTL
);
if( actions
& CVTR
) p
= convert( p
, CVTR
);
if( actions
& TYMATCH
) p
= tymatch(p
);
if( actions
& PTMATCH
) p
= ptmatch(p
);
if( sp
->stype
== UNDEF
){
uerror( "%.8s undefined", sp
->sname
);
uerror( "%s undefined", sp
->sname
);
/* make p look reasonable */
p
->in
.type
= p
->fn
.cdim
= p
->fn
.csiz
= INT
;
/* special case: MOETY is really an ICON... */
if( p
->in
.type
== MOETY
){
/* p->x turned into *(p+offset) */
/* rhs must be a name; check correctness */
if( i
<0 || ((sp
= &stab
[i
])->sclass
!= MOS
&& sp
->sclass
!= MOU
&& !(sp
->sclass
&FIELD
)) ){
uerror( "member of structure or union required" );
/* if this name is non-unique, find right one */
if( stab
[i
].sflags
& SNONUNIQ
&&
(l
->in
.type
==PTR
+STRTY
|| l
->in
.type
== PTR
+UNIONTY
) &&
/* nonunique name && structure defined */
for( ; (memi
=dimtab
[j
]) >= 0; ++j
){
tabnam
= stab
[memi
].sname
;
printf("member %.8s==%.8s?\n",
printf("member %s==%s?\n",
if( stab
[memi
].sflags
& SNONUNIQ
){
for( k
=0; k
<NCHNAM
; ++k
){
uerror("illegal member use: %.8s",
uerror("illegal member use: %s",
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: %.8s", stab
[i
].sname
);
werror( "illegal member use: %s", stab
[i
].sname
);
if( l
->in
.op
== UNARY AND
){
p
->in
.op
= l
->in
.op
= FREE
;
if( !ISPTR(l
->in
.type
))uerror("illegal indirection");
p
->in
.type
= DECREF(l
->in
.type
);
p
->in
.op
= l
->in
.op
= FREE
;
p
->in
.type
= INCREF( l
->in
.type
);
lr
= buildtree( UNARY AND
, l
->in
.right
, NIL
);
p
->in
.op
= l
->in
.op
= FREE
;
p
= buildtree( COMOP
, l
->in
.left
, lr
);
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
) );
/* OREG was built in clocal()
* for an auto or formal parameter
* now its address is being taken
* local code must unwind it
* back to PLUS/MINUS REG ICON
* according to local conventions
extern NODE
* addroreg();
uerror( "unacceptable operand of &" );
if(tsize(p
->in
.right
->in
.type
, p
->in
.right
->fn
.cdim
, p
->in
.right
->fn
.csiz
) > SZINT
)
p
->in
.right
= makety(p
->in
.right
, INT
, 0, INT
);
/* structure assignment */
/* take the addresses of the two sides; then make an
/* operator using STASG and
/* the addresses of left and right */
if( l
->fn
.csiz
!= r
->fn
.csiz
) uerror( "assignment of different structures" );
r
= buildtree( UNARY AND
, r
, NIL
);
l
= block( STASG
, l
, r
, t
, d
, s
);
if( l
->fn
.csiz
!= r
->fn
.csiz
) uerror( "type clash in conditional" );
p
->in
.right
= r
= fixargs( p
->in
.right
);
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
);
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 */
/* make function really return ptr to str., with * */
p
->in
.type
= INCREF( p
->in
.type
);
p
= buildtree( UNARY MUL
, p
, NIL
);
cerror( "other code %d", o
);
if( actions
& CVTO
) p
= oconvert(p
);
if( bdebug
) fwalk( p
, eprint
, 0 );
cerror("floating point exception");
* Rewrite arguments in a function call.
* Structure arguments are massaged, single
* precision floating point constants are
* cast to double (to eliminate convert code).
fixargs( p
) register NODE
*p
; {
p
->in
.left
= fixargs( p
->in
.left
);
p
->in
.right
= fixargs( p
->in
.right
);
if( p
->in
.type
== STRTY
|| p
->in
.type
== UNIONTY
){
p
= block( STARG
, p
, NIL
, p
->in
.type
, p
->fn
.cdim
, p
->fn
.csiz
);
p
->in
.left
= buildtree( UNARY AND
, p
->in
.left
, NIL
);
p
= makety(p
, DOUBLE
, 0, 0);
chkstr( i
, j
, type
) TWORD type
; {
/* 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... */
if( ddebug
> 1 ) printf( "chkstr( %.8s(%d), %d )\n", stab
[i
].sname
, i
, j
);
if( ddebug
> 1 ) printf( "chkstr( %s(%d), %d )\n", stab
[i
].sname
, i
, j
);
if( (k
= j
) < 0 ) uerror( "undefined structure or union" );
for( ; (kk
= dimtab
[k
] ) >= 0; ++k
){
cerror( "gummy structure" );
if( kk
== i
) return( 1 );
switch( stab
[kk
].stype
){
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 */
"illegal member use: perhaps %.8s.%.8s?",
"illegal member use: perhaps %s.%s?",
stab
[kk
].sname
, stab
[i
].sname
);
conval( p
, o
, q
) register NODE
*p
, *q
; {
/* apply the op o to the lval part of p; if binary, rhs is val */
/* works only on integer constants */
u
= ISUNSIGNED(p
->in
.type
) || ISUNSIGNED(q
->in
.type
);
if( u
&& (o
==LE
||o
==LT
||o
==GE
||o
==GT
)) o
+= (UGE
-GE
);
if( p
->tn
.rval
!= NONAME
&& q
->tn
.rval
!= NONAME
) return(0);
if( q
->tn
.rval
!= NONAME
&& o
!=PLUS
) return(0);
if( p
->tn
.rval
!= NONAME
&& o
!=PLUS
&& o
!=MINUS
) return(0);
if( p
->in
.type
!= INT
|| q
->in
.type
!= INT
){
/* will this always work if p == q and o is UTYPE? */
r
= block( o
, p
, q
, INT
, 0, INT
);
if( p
->tn
.rval
== NONAME
){
if( val
== 0 ) uerror( "division by 0" );
else if ( u
) p
->tn
.lval
= (unsigned) p
->tn
.lval
/ val
;
if( val
== 0 ) uerror( "division by 0" );
else if ( u
) p
->tn
.lval
= (unsigned) p
->tn
.lval
% val
;
p
->tn
.lval
= p
->tn
.lval
<< i
;
if ( u
) p
->tn
.lval
= (unsigned) p
->tn
.lval
>> i
;
else p
->tn
.lval
= p
->tn
.lval
>> i
;
p
->tn
.lval
= - p
->tn
.lval
;
p
->tn
.lval
= ~p
->tn
.lval
;
p
->tn
.lval
= !p
->tn
.lval
;
p
->tn
.lval
= p
->tn
.lval
< val
;
p
->tn
.lval
= p
->tn
.lval
<= val
;
p
->tn
.lval
= p
->tn
.lval
> val
;
p
->tn
.lval
= p
->tn
.lval
>= val
;
p
->tn
.lval
= p
->tn
.lval
< (unsigned) val
;
p
->tn
.lval
= p
->tn
.lval
<= (unsigned) val
;
p
->tn
.lval
= p
->tn
.lval
> (unsigned) val
;
p
->tn
.lval
= p
->tn
.lval
>= (unsigned) val
;
p
->tn
.lval
= p
->tn
.lval
== val
;
p
->tn
.lval
= p
->tn
.lval
!= val
;
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 type */
/* we check that this integer is in fact a constant zero... */
/* in the case of ASSIGN, any assignment of pointer to integer is illegal */
/* this falls out, because the LHS is never 0 */
t1
= p
->in
.left
->in
.type
;
t2
= p
->in
.right
->in
.type
;
if( t1
==ENUMTY
|| t2
==ENUMTY
) { /* check for enumerations */
/* rob pike says this is obnoxious...
if( logop( p->in.op ) && p->in.op != EQ && p->in.op != NE )
werror( "comparison of enums" ); */
if( t1
==ENUMTY
&& t2
==ENUMTY
) {
if ( p
->in
.left
->fn
.csiz
!=p
->in
.right
->fn
.csiz
)
werror( "enumeration type clash, operator %s", opst
[p
->in
.op
] );
if ( t1
== ENUMTY
) t1
= INT
;
if ( t2
== ENUMTY
) t2
= INT
;
ref1
= ISPTR(t1
) || ISARY(t1
);
ref2
= ISPTR(t2
) || ISARY(t2
);
if( ref1
) q
= p
->in
.right
;
if( q
->in
.op
!= ICON
|| q
->tn
.lval
!= 0 ){
werror( "illegal combination of pointer and integer, op %s",
if( p
->in
.left
->fn
.csiz
!= p
->in
.right
->fn
.csiz
) {
werror( "illegal structure pointer combination" );
d1
= p
->in
.left
->fn
.cdim
;
d2
= p
->in
.right
->fn
.cdim
;
if( dimtab
[d1
] != dimtab
[d2
] ){
werror( "illegal array size combination" );
else if( !ISPTR(t1
) ) break;
werror( "illegal pointer combination" );
stref( p
) register NODE
*p
; {
register struct symtab
*q
;
/* this is also used to reference automatic variables */
q
= &stab
[p
->in
.right
->tn
.rval
];
p
->in
.right
->in
.op
= FREE
;
p
= pconvert( p
->in
.left
);
/* make p look like ptr to x */
p
->in
.type
= PTR
+UNIONTY
;
p
= makety( p
, t
, d
, s
);
/* compute the offset to be added */
if( dsc
& FIELD
) { /* normalize offset */
if( off
!= 0 ) p
= clocal( block( PLUS
, p
, offcon( off
, t
, d
, s
), t
, d
, s
) );
p
= buildtree( UNARY MUL
, p
, NIL
);
/* if field, build field info */
p
= block( FLD
, p
, NIL
, q
->stype
, 0, q
->sizoff
);
p
->tn
.rval
= PKFIELD( dsc
&FLDSIZ
, q
->offset
%align
);
notlval(p
) register NODE
*p
; {
/* return 0 if p an lvalue, 1 otherwise */
/* fix the &(a=b) bug, given that a and b are structures */
if( p
->in
.left
->in
.op
== STASG
) return( 1 );
/* and the f().a bug, given that f returns a structure */
if( p
->in
.left
->in
.op
== UNARY STCALL
||
p
->in
.left
->in
.op
== STCALL
) return( 1 );
if( ISARY(p
->in
.type
) || ISFTN(p
->in
.type
) ) return(1);
bcon( i
){ /* make a constant node with value i */
p
= block( ICON
, NIL
, NIL
, INT
, 0, INT
);
bpsize(p
) register NODE
*p
; {
return( offcon( psize(p
), p
->in
.type
, p
->fn
.cdim
, p
->fn
.csiz
) );
/* p is a node of type pointer; psize returns the
size of the thing pointed to */
if( !ISPTR(p
->in
.type
) ){
uerror( "pointer required");
/* note: no pointers to fields */
return( tsize( DECREF(p
->in
.type
), p
->fn
.cdim
, p
->fn
.csiz
) );
convert( p
, f
) register NODE
*p
; {
/* convert an operand of p
operand has type int, and is converted by the size of the other side
q
= (f
==CVTL
)?p
->in
.left
:p
->in
.right
;
q
, bpsize(f
==CVTL
?p
->in
.right
:p
->in
.left
), INT
, 0, INT
);
econvert( p
) register NODE
*p
; {
/* change enums to ints, or appropriate types */
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
;
if( p
->in
.op
== ICON
&& ty
!= LONG
) p
->in
.type
= p
->fn
.csiz
= INT
;
pconvert( p
) register NODE
*p
; {
/* if p should be changed into a pointer, do so */
if( ISARY( p
->in
.type
) ){
p
->in
.type
= DECREF( p
->in
.type
);
return( buildtree( UNARY AND
, p
, NIL
) );
return( buildtree( UNARY AND
, p
, NIL
) );
oconvert(p
) register NODE
*p
; {
/* convert the result itself: used for pointer and unsigned */
if( ISUNSIGNED(p
->in
.left
->in
.type
) || ISUNSIGNED(p
->in
.right
->in
.type
) ) p
->in
.op
+= (ULE
-LE
);
return( clocal( block( PVCONV
,
p
, bpsize(p
->in
.left
), INT
, 0, INT
) ) );
cerror( "illegal oconvert: %d", p
->in
.op
);
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 */
t
= t1
= p
->in
.left
->in
.type
;
t2
= p
->in
.right
->in
.type
;
d2
= p
->in
.right
->fn
.cdim
;
s2
= p
->in
.right
->fn
.csiz
;
{ if( psize(p
->in
.left
) != psize(p
->in
.right
) ){
uerror( "illegal pointer subtraction");
{ if( t1
!= t2
) uerror( "illegal types in :");
default: /* must work harder: relationals or comparisons */
if( talign(t2
,s2
) < talign(t
,s
) ){
p
->in
.left
= makety( p
->in
.left
, t
, d
, s
);
p
->in
.right
= makety( p
->in
.right
, t
, d
, s
);
if( o
!=MINUS
&& !logop(o
) ){
tymatch(p
) register NODE
*p
; {
/* satisfy the types of various arithmetic binary ops */
if assignment, type of LHS
if any float or doubles, make double
if either operand is unsigned, the result is...
register TWORD t1
, t2
, t
, tu
;
t1
= p
->in
.left
->in
.type
;
t2
= p
->in
.right
->in
.type
;
if( (t1
==UNDEF
|| t2
==UNDEF
) && o
!=CAST
)
uerror("void type illegal in expression");
if( ( t1
== CHAR
|| t1
== SHORT
) && o
!= RETURN
) t1
= INT
;
if( t2
== CHAR
|| t2
== SHORT
) t2
= INT
;
if( t1
== DOUBLE
|| t2
== DOUBLE
)
else if( t1
== FLOAT
|| t2
== FLOAT
)
if (t1
== DOUBLE
|| t1
== FLOAT
|| t2
== DOUBLE
|| t2
== FLOAT
)
else if( t1
==LONG
|| t2
==LONG
) t
= LONG
;
if( o
== ASSIGN
|| o
== CAST
|| o
== RETURN
)
tu
= p
->in
.left
->in
.type
;
tu
= (u
&& UNSIGNABLE(t
))?ENUNSIGN(t
):t
;
/* because expressions have values that are at least as wide
as INT or UNSIGNED, the only conversions needed
are those involving FLOAT/DOUBLE, and those
from LONG to INT and ULONG to UNSIGNED */
if( t
!= t1
&& ! asgop(o
) )
p
->in
.left
= makety( p
->in
.left
, tu
, 0, (int)tu
);
if ( tu
== ENUMTY
) {/* always asgop */
p
->in
.right
= makety( p
->in
.right
, INT
, 0, INT
);
p
->in
.right
->in
.type
= tu
;
p
->in
.right
->fn
.cdim
= p
->in
.left
->fn
.cdim
;
p
->in
.right
->fn
.csiz
= p
->in
.left
->fn
.csiz
;
p
->in
.right
= makety( p
->in
.right
, tu
, 0, (int)tu
);
p
->in
.type
= p
->in
.left
->in
.type
;
p
->fn
.cdim
= p
->in
.left
->fn
.cdim
;
p
->fn
.csiz
= p
->in
.left
->fn
.csiz
;
if( tdebug
) printf( "tymatch(%o): %o %s %o => %o\n",p
,t1
,opst
[o
],t2
,tu
);
makety( p
, t
, d
, s
) register NODE
*p
; TWORD t
; {
/* make p into type t by inserting a conversion */
if( p
->in
.type
== ENUMTY
&& p
->in
.op
== ICON
) econvert(p
);
return( block( PCONV
, p
, NIL
, t
, d
, s
) );
if (ISUNSIGNED(p
->in
.type
))
p
->dpn
.dval
= (unsigned CONSZ
) p
->tn
.lval
;
p
->dpn
.dval
= p
->tn
.lval
;
p
->in
.type
= p
->fn
.csiz
= t
;
if( ISUNSIGNED(p
->in
.type
) ){
p
->fpn
.fval
= (unsigned CONSZ
) p
->tn
.lval
;
p
->fpn
.fval
= p
->tn
.lval
;
p
->in
.type
= p
->fn
.csiz
= t
;
else if (p
->in
.op
== FCON
&& t
== DOUBLE
) {
p
->in
.type
= p
->fn
.csiz
= t
;
} else if (p
->in
.op
== DCON
&& t
== FLOAT
) {
werror("float conversion loses precision");
p
->in
.type
= p
->fn
.csiz
= t
;
return( clocal( block( SCONV
, p
, NIL
, t
, d
, s
) ) );
block( o
, l
, r
, t
, d
, s
) register NODE
*l
, *r
; TWORD t
; {
icons(p
) register NODE
*p
; {
/* if p is an integer constant, return its value */
uerror( "constant expected");
if( val
!= p
->tn
.lval
) uerror( "constant too big for cross-compiler" );
/* the intent of this table is to examine the
operators, and to check them for
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:
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
NCVT do not convert the operands
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 */
# define MVOID 0100000 /* void type */
register mt12
, mt1
, mt2
, o
;
switch( optype(o
=p
->in
.op
) ){
mt2
= moditype( p
->in
.right
->in
.type
);
mt1
= moditype( p
->in
.left
->in
.type
);
if( ((mt1
| mt2
) & MVOID
) &&
!(o
== QUEST
&& (mt1
& MVOID
) == 0) &&
!(o
== CAST
&& (mt1
& MVOID
)) ){
/* if lhs of RETURN is void, grammar will complain */
uerror( "value of void expression used" );
if( mt1
& MENU
) return( 0 );
if( mt1
& MDBI
) return( TYPL
);
if( mt1
& MENU
) return( 0 );
if( mt1
& MINT
) return( TYPL
);
{ return( NCVT
+OTHER
); }
if( (mt1
& MSTR
) || (mt2
& MSTR
) ) break;
if( mt12
& MDBI
) return( TYMATCH
);
if( mt12
& MINT
) return( TYMATCH
);
if( mt12
& MINT
) return( TYMATCH
+OTHER
);
if( mt12
& MENU
) return( TYMATCH
+NCVT
+PUN
);
if( mt12
& MDBI
) return( TYMATCH
+NCVT
+CVTO
);
else if( mt12
& MPTR
) return( PTMATCH
+PUN
);
else if( mt12
& MPTI
) return( PTMATCH
+PUN
);
if( mt2
&MENU
) return( TYPR
+NCVTR
);
if( mt12
& MENU
) return( NCVT
+PUN
+TYMATCH
);
else if( mt12
& MDBI
) return( NCVT
+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
);
else if( mt12
== MVOID
) return( NCVT
+TYPL
);
if( mt12
& MSTR
) return( LVAL
+NCVT
+TYPL
+OTHER
);
else if( mt12
& MENU
) return( LVAL
+NCVT
+TYPL
+TYMATCH
+PUN
);
if(o
==CAST
&& mt1
==MVOID
)return(TYPL
+TYMATCH
);
else if( mt12
& MDBI
) return( TYPL
+LVAL
+NCVT
+TYMATCH
);
( p
->in
.right
->in
.op
== CALL
||
p
->in
.right
->in
.op
== UNARY CALL
)) break;
else if( (mt1
& MPTR
) && (mt2
& MPTI
) )
return( LVAL
+PTMATCH
+PUN
);
else if( mt12
& MPTI
) return( TYPL
+LVAL
+TYMATCH
+PUN
);
if( mt12
& MINT
) return( TYPL
+LVAL
+OTHER
);
if( mt12
& MDBI
) return( LVAL
+TYMATCH
);
if( mt12
& MINT
) return( LVAL
+TYMATCH
);
if( mt12
& MDBI
) return( TYMATCH
+LVAL
);
else if( (mt1
&MPTR
) && (mt2
&MINT
) ) return( TYPL
+LVAL
+CVTR
);
if( mt12
& MPTR
) return( CVTO
+PTMATCH
+PUN
);
if( mt12
& MDBI
) return( TYMATCH
);
else if( (mt1
&MPTR
) && (mt2
&MINT
) ) return( TYPL
+CVTR
);
else if( (mt1
&MINT
) && (mt2
&MPTR
) ) return( TYPR
+CVTL
);
uerror( "%s is not a permitted struct/union operation", opst
[o
] );
uerror( "operands of %s have incompatible types", opst
[o
] );
moditype( ty
) TWORD ty
; {
return( MENU
|MINT
|MDBI
|MPTI
); /* enums are ints */
return( MINT
|MPTI
|MDBI
);
return( MINT
|MDBI
|MPTI
);
doszof( p
) register NODE
*p
; {
/* whatever is the meaning of this if it is a bitfield? */
i
= tsize( p
->in
.type
, p
->fn
.cdim
, p
->fn
.csiz
)/SZCHAR
;
if( i
<= 0 ) werror( "sizeof returns 0" );
eprint( p
, down
, a
, b
) register NODE
*p
; int *a
, *b
; {
if( down
) printf( " " );
printf("%o) %s, ", p
, opst
[p
->in
.op
] );
printf( CONFMT
, p
->tn
.lval
);
printf( ", %d, ", p
->tn
.rval
);
printf( ", %d, %d\n", p
->fn
.cdim
, p
->fn
.csiz
);
prtdcon( p
) register NODE
*p
; {
if( o
== DCON
|| o
== FCON
){
defalign( o
== DCON
? ALDOUBLE
: ALFLOAT
);
fincode( p
->fpn
.fval
, SZFLOAT
);
fincode( p
->dpn
.dval
, SZDOUBLE
);
p
->in
.type
= (o
== DCON
? DOUBLE
: FLOAT
);
ecomp( p
) register NODE
*p
; {
if( edebug
) fwalk( p
, eprint
, 0 );
werror( "statement not reached" );
prtree(p
) register NODE
*p
; {
register struct symtab
*q
;
MYPRTREE(p
); /* local action can be taken here; then return... */
printf( "%d\t", p
->in
.op
);
printf( CONFMT
, p
->tn
.lval
);
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 */
/* print external name */
if( p
->tn
.rval
== NONAME
) printf( "\n" );
else if( p
->tn
.rval
>= 0 ){
printf( "%s\n", exname(q
->sname
) );
printf( LABFMT
, -p
->tn
.rval
);
/* 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
) );
if( ty
!= LTYPE
) prtree( p
->in
.left
);
if( ty
== BITYPE
) prtree( p
->in
.right
);
p2tree(p
) register NODE
*p
; {
MYP2TREE(p
); /* local action can be taken here; then return... */
if( p
->tn
.rval
== NONAME
) p
->in
.name
[0] = '\0';
if( p
->tn
.rval
== NONAME
) p
->in
.name
= "";
else if( p
->tn
.rval
>= 0 ){ /* copy name from exname */
cp
= exname( stab
[p
->tn
.rval
].sname
);
for( i
=0; i
<NCHNAM
; ++i
)
else sprintf( p
->in
.name
, LABFMT
, -p
->tn
.rval
);
sprintf( temp
, LABFMT
, -p
->tn
.rval
);
/* set up size parameters */
p
->stn
.stsize
= (tsize(STRTY
,p
->in
.left
->fn
.cdim
,p
->in
.left
->fn
.csiz
)+SZCHAR
-1)/SZCHAR
;
p
->stn
.stalign
= talign(STRTY
,p
->in
.left
->fn
.csiz
)/SZCHAR
;
rbusy( p
->tn
.rval
, p
->in
.type
);
if( ty
!= LTYPE
) p2tree( p
->in
.left
);
if( ty
== BITYPE
) p2tree( p
->in
.right
);