895 lines
17 KiB
C
895 lines
17 KiB
C
# include "mfile2.h"
|
|
# ifdef SDB
|
|
# include "sdb.h"
|
|
# endif
|
|
#ifndef NONAME
|
|
#define NONAME 040000
|
|
#endif
|
|
|
|
int fldsz, fldshf;
|
|
|
|
int sdebug = 0;
|
|
int zflag = 0; /* non-zero to output stin line and cost for
|
|
** each assembly instruction
|
|
*/
|
|
|
|
ttype( t )
|
|
register TWORD t;
|
|
{
|
|
/* return the coded type of t */
|
|
/* this is called only from the first pass */
|
|
|
|
# ifdef TWOPTRS
|
|
if( ISPTR(t) )
|
|
{
|
|
do
|
|
{
|
|
t = DECREF(t);
|
|
} while ( ISARY(t) );
|
|
/* arrays that are left are usually only
|
|
** in structure references...
|
|
*/
|
|
if( TWOPTRS(t) ) return( TPOINT2 );
|
|
return( TPOINT );
|
|
}
|
|
# endif
|
|
|
|
if( t != BTYPE(t) ) return( TPOINT ); /* TPOINT means not simple! */
|
|
|
|
switch( t )
|
|
{
|
|
|
|
case CHAR:
|
|
return( TCHAR );
|
|
case SHORT:
|
|
return( TSHORT );
|
|
case STRTY:
|
|
case UNIONTY:
|
|
return( TSTRUCT );
|
|
case INT:
|
|
return( TINT );
|
|
case UNSIGNED:
|
|
return( TUNSIGNED );
|
|
case USHORT:
|
|
return( TUSHORT );
|
|
case UCHAR:
|
|
return( TUCHAR );
|
|
case ULONG:
|
|
return( TULONG );
|
|
case LONG:
|
|
return( TLONG );
|
|
case FLOAT:
|
|
return( TFLOAT );
|
|
case DOUBLE:
|
|
return( TDOUBLE );
|
|
case VOID:
|
|
return( TVOID );
|
|
}
|
|
cerror( "ttype(0%o)", t );
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
# define VALUE (RESC1|RESC2|RESC3|RLEFT|RRIGHT)
|
|
|
|
OPTAB *
|
|
match( p, q )
|
|
register NODE *p;
|
|
register OPTAB *q;
|
|
{
|
|
/* look for match in table */
|
|
/* given a tree, p, and a template q, returns the next template that
|
|
/* matches p */
|
|
/* q == NULL starts the process off */
|
|
/* match is not called recursively, so much of the setup can be done
|
|
/* into static variables */
|
|
|
|
static NODE *r, *l;
|
|
static tl, tr, goal, tyop;
|
|
static pop, lflg;
|
|
int rr;
|
|
|
|
if( !q ) {
|
|
/* startup code */
|
|
|
|
q = ophead[pop=p->tn.op];
|
|
l = getlo( p, pop ); /* left child */
|
|
r = getro( p, pop ); /* right child */
|
|
tl = l->in.type;
|
|
tr = r->in.type;
|
|
lflg = asgop(pop); /* forces a match on lvalues */
|
|
if( p->tn.goal == CCC ) goal = (VALUE|RESCC);
|
|
else if( p->tn.goal == NRGS ) goal = VALUE;
|
|
else goal = ~0;
|
|
tyop = p->in.type;
|
|
}
|
|
|
|
else {
|
|
if( fast ) return( (OPTAB *)0 ); /* only first match */
|
|
else q = q->nextop;
|
|
}
|
|
if( !q ) return( (OPTAB *)0 );
|
|
|
|
# ifndef NODBG
|
|
if( sdebug ) {
|
|
printf( "match tree %d, op %s, p->tn.goal 0x%x\n",
|
|
(unsigned short)(p-node), opst[pop], p->tn.goal );
|
|
printf("linker typ = 0x%x, rechts = 0x%x, goal = 0x%x\n",tl,tr,goal);
|
|
}
|
|
# endif
|
|
for( ; q ; q = q->nextop ){
|
|
|
|
/* some templates are no good for computing values */
|
|
if(sdebug > 3)
|
|
printf("versuch line %d,ltyp = 0x%x, rtyp = 0x%x, goal = 0x%x\n",
|
|
q->stinline,q->ltype,q->rtype,q->rewrite);
|
|
|
|
if( !( tl & q->ltype ) ) continue;
|
|
if( !( tr & q->rtype ) ) continue;
|
|
|
|
if( !( goal & q->rewrite ) ) continue;
|
|
|
|
# ifndef NODBG
|
|
if( sdebug ) {
|
|
printf( " try table entry, line %d, op %s q->rewrite %x\n",
|
|
q->stinline, opst[q->op], q->rewrite );
|
|
}
|
|
# endif
|
|
if( !( tyop & q->tyop ) ) {
|
|
# ifndef NODBG
|
|
if( sdebug ) {
|
|
printf(
|
|
"\tentry line %d fails tyop, %o vs %o\n",
|
|
q->stinline, tyop, q->tyop );
|
|
}
|
|
# endif
|
|
continue;
|
|
}
|
|
|
|
if( q->rshape ){
|
|
if( rr=mspine( q->rshape, (q->lshape)?r:p, 0, sha[1] )){
|
|
sha[1][rr] = 0;
|
|
if( !q->lshape ) ustrip(pop);
|
|
}
|
|
else continue;
|
|
}
|
|
else {
|
|
sha[1][1] = sha[1][0] = (SHAPE *)0;
|
|
}
|
|
|
|
if( q->lshape ){
|
|
if( !lflg && asgop(q->op) ){
|
|
/* q->op is an assignment op, pop isn't */
|
|
/* thus, the lhs => a register or temp */
|
|
rr = rtspine( q->lshape, p );
|
|
}
|
|
else rr = mspine( q->lshape, l, lflg, sha[0] );
|
|
if( rr ) sha[0][rr] = 0;
|
|
else continue;
|
|
}
|
|
else {
|
|
sha[0][1] = sha[0][0] = (SHAPE *)0;
|
|
}
|
|
|
|
/* at this point, we have a match */
|
|
|
|
# ifndef NODBG
|
|
if( sdebug ) {
|
|
printf( "table line %d matches tree %d\n",
|
|
q->stinline, p-node );
|
|
}
|
|
# endif
|
|
|
|
return( q ); /* found match */
|
|
}
|
|
return( (OPTAB *)0 );
|
|
}
|
|
|
|
ustrip( o )
|
|
{
|
|
/* strip out of sha[1] all shapes with op != o */
|
|
/* sty should do this someday, but for now, it's done here */
|
|
register i, j;
|
|
|
|
for( j=i=0; sha[1][j]; ++j ) {
|
|
if( sha[1][j]->op == o ) sha[1][i++] = sha[1][j];
|
|
}
|
|
sha[1][i] = (SHAPE *)0;
|
|
}
|
|
|
|
rtspine( ps, p )
|
|
SHAPE **ps;
|
|
NODE *p; {
|
|
/* special routine to put the lhs into a reg or a temp */
|
|
/* looks for reg and/or temp in s */
|
|
/* makes a list in sha[0] */
|
|
register rr;
|
|
register SHAPE *s;
|
|
|
|
for( rr = 0; s = *ps; ++ps ) {
|
|
/* works because FREE, CCODES, REG, and TEMP are first */
|
|
switch( s->op ) {
|
|
|
|
case FREE:
|
|
case CCODES:
|
|
continue;
|
|
|
|
case REG:
|
|
case TEMP:
|
|
if( s->sh ) if( !spshape( s->sh, p ) ) continue;
|
|
if( rr >= NSHP-1 ) cerror( "too many shapes" );
|
|
sha[0][rr] = s;
|
|
++rr;
|
|
continue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return( rr );
|
|
}
|
|
|
|
restrip( pls )
|
|
register SHAPE **pls;
|
|
{
|
|
/* throw away those shapes that can't be results */
|
|
register SHAPE **p;
|
|
|
|
for( p=pls; *p = *pls; ++p, ++pls )
|
|
{
|
|
if( noresult( *p ) ) --p; /* overwrite if result is illegal */
|
|
}
|
|
}
|
|
|
|
noresult( s )
|
|
register SHAPE *s;
|
|
{
|
|
if( !s ) return( 0 );
|
|
if( s->op == INCR || s->op == DECR ) return( 1 );
|
|
return( (s->sr && noresult(s->sr)) ||
|
|
(s->sl && noresult( s->sl )) );
|
|
}
|
|
|
|
smspine( s, p, flag )
|
|
register NODE *p;
|
|
register SHAPE *s;
|
|
{
|
|
/* match the spine of s, including special shapes */
|
|
/* this is a submatch, called only by mspine */
|
|
/* flag is nonzero if STAR's must be skipped */
|
|
|
|
register sop, pop;
|
|
|
|
again:
|
|
|
|
sop = s->op;
|
|
pop = p->tn.op;
|
|
|
|
# ifndef NODBG
|
|
if( sdebug>1 )
|
|
{
|
|
printf( " smspine(%d[%s], %d[%s])\n",
|
|
s-shapes, opst[sop], p-node, opst[pop] );
|
|
}
|
|
# endif
|
|
|
|
if( ( s->sh ) && !spshape( s->sh,p) ) return( 0 );
|
|
if( sop != pop )
|
|
{
|
|
if( sop == CCODES || sop == FREE ) return(1);
|
|
return( !flag && (sop==REG || sop==TEMP) );
|
|
}
|
|
if( sop == STAR )
|
|
{
|
|
flag = 0;
|
|
goto recurse;
|
|
}
|
|
switch( optype( sop ) )
|
|
{
|
|
|
|
case BITYPE:
|
|
if( !smspine( s->sr, p->in.right, 0 ) ) return(0);
|
|
flag = asgop(sop);
|
|
/* FALLTHRU */
|
|
|
|
case UTYPE:
|
|
recurse:
|
|
s = s->sl;
|
|
p = p->in.left;
|
|
goto again;
|
|
|
|
default:
|
|
return( 1 );
|
|
}
|
|
}
|
|
|
|
mspine( ps, p, flag, ppls )
|
|
register NODE *p;
|
|
register SHAPE **ps;
|
|
register SHAPE **ppls;
|
|
{
|
|
/* match the spine of s, including special shapes */
|
|
/* s points to a list of shapes */
|
|
/* those shapes that match are copied into **ppls, with a null at end */
|
|
/* flag = 1 forces regs and temps to match exactly */
|
|
/* rr, the number of matches, is returned */
|
|
|
|
register SHAPE *s;
|
|
int pop, rr;
|
|
|
|
# ifndef NODBG
|
|
if( sdebug )
|
|
{
|
|
printf( "\tmspine( %d, %d, %d )\n", ps-pshape, p-node, flag );
|
|
}
|
|
# endif
|
|
pop = p->tn.op;
|
|
|
|
/* copy the wild-cards, and those where the op matches */
|
|
for( rr=0; s = *ps; ++ps )
|
|
{
|
|
switch( s->op )
|
|
{
|
|
|
|
case REG:
|
|
case TEMP:
|
|
if( flag ) break;
|
|
if( s->sh ) if( !spshape(s->sh,p) ) continue;
|
|
/* FALLTHRU */
|
|
|
|
case FREE:
|
|
case CCODES:
|
|
if( rr >= NSHP-1 ) cerror( "too many shapes" );
|
|
|
|
# ifndef NODBG
|
|
if( sdebug )
|
|
{
|
|
printf(
|
|
"\t\tmspine( %d[%s], %d[%s] ), becomes %d\n",
|
|
s-shapes, opst[s->op], p-node,
|
|
opst[pop], rr );
|
|
}
|
|
# endif
|
|
|
|
ppls[rr++] = s;
|
|
continue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* now, either s is 0 or s has a "real" op */
|
|
/* the first condition survives the next two loops */
|
|
|
|
/* we have matched the wild cards: find others where the op matches */
|
|
|
|
for( ; (s= *ps) && s->op != pop; ++ps )
|
|
{
|
|
;
|
|
}
|
|
|
|
/* now, s is null or matches the op of p */
|
|
for( ; (s = *ps) && s->op == pop; ++ps )
|
|
{
|
|
|
|
if( pop == STAR )
|
|
{
|
|
if( !smspine( s->sl, p->in.left, 0 ) ) continue;
|
|
}
|
|
|
|
/* general case: check the subtrees also */
|
|
else if( s->sl )
|
|
{
|
|
if( s->sr )
|
|
{
|
|
if( !smspine( s->sr, p->in.right, 0 ) )
|
|
continue;
|
|
if( !smspine( s->sl, p->in.left, asgop(s->op)) )
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if( !smspine( s->sl, p->in.left, flag ))
|
|
continue;
|
|
}
|
|
}
|
|
else if( s->sr && !smspine( s->sr, p->in.right, 0 ) )
|
|
continue;
|
|
|
|
/* if we get this far, we are in good shape */
|
|
|
|
if( s->sh ) if( !spshape( s->sh, p ) ) continue;
|
|
if( rr >= NSHP-1 ) cerror( "too many shapes" );
|
|
|
|
# ifndef NODBG
|
|
if( sdebug )
|
|
{
|
|
printf( "\t\tmspine( %d[%s], %d[%s] ), becomes %d\n",
|
|
s-shapes, opst[s->op], p-node,
|
|
opst[pop], rr );
|
|
}
|
|
# endif
|
|
|
|
ppls[rr++] = s;
|
|
}
|
|
|
|
/* fall out and we are done */
|
|
return( rr );
|
|
}
|
|
|
|
|
|
tempok( p )
|
|
NODE *p;
|
|
|
|
{
|
|
/* decide if the result of p is OK as a temp */
|
|
int o;
|
|
if( (o = p->tn.op) == TEMP ) return( 1 );
|
|
if( asgop(o) && o!=INCR && o!=DECR )
|
|
{
|
|
return( p->in.left->tn.op == TEMP );
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
int sideff;
|
|
|
|
rmside( p )
|
|
NODE *p;
|
|
|
|
{
|
|
/* p is a tree with side effects: remove them */
|
|
/* this is done in place */
|
|
int o;
|
|
NODE *q;
|
|
|
|
o = p->tn.op;
|
|
switch( o )
|
|
{
|
|
|
|
case INCR:
|
|
case DECR:
|
|
case ASG PLUS:
|
|
case ASG MINUS:
|
|
if( p->in.right->tn.op == ICON ) p->in.right->tn.op = FREE;
|
|
else
|
|
{
|
|
regrcl( p->in.right );
|
|
tfree( p->in.right );
|
|
}
|
|
q = p->in.left;
|
|
*p = *q;
|
|
q->tn.op = FREE;
|
|
rmside( p );
|
|
return;
|
|
}
|
|
|
|
switch( optype( o ) )
|
|
{
|
|
|
|
case BITYPE:
|
|
rmside( p->in.right );
|
|
case UTYPE:
|
|
rmside( p->in.left );
|
|
}
|
|
}
|
|
|
|
expand( p, goal, cp, q )
|
|
NODE *p;
|
|
char *cp;
|
|
OPTAB *q;
|
|
{
|
|
/* generate code by interpreting table entry */
|
|
|
|
CONSZ val;
|
|
NODE *q1, *q2;
|
|
int c, typ, v;
|
|
TWORD t;
|
|
|
|
/*# ifdef SDB
|
|
/* if( (c = p->tn.op) == CALL || c == UNARY CALL )
|
|
/* {
|
|
/* /* number of args (for sdb) */
|
|
/* pstab( S_NARGS, (int)(p->stn.argsize/SZINT));
|
|
/* }
|
|
/*# endif
|
|
/**/
|
|
if(p->in.op == SHIFTOP && p->in.right->in.op==ICON) {
|
|
typ = p->in.left->tn.type;
|
|
v = p->in.right->tn.lval;
|
|
if(typ & TLONG || typ & TULONG || typ & TPOINT) {
|
|
if(v > 32)
|
|
p->in.right->tn.lval = 32;
|
|
} else if(typ & TCHAR || typ & TUCHAR) {
|
|
if(v > 8)
|
|
p->in.right->tn.lval = 8;
|
|
} else if (v > 16)
|
|
p->in.right->tn.lval = 16;
|
|
}
|
|
|
|
for( ; *cp; ++cp )
|
|
{
|
|
switch( *cp )
|
|
{
|
|
|
|
case '\\':
|
|
++cp;
|
|
/* FALLTHRU */
|
|
default:
|
|
PUTCHAR( *cp );
|
|
continue; /* this is the usual case... */
|
|
|
|
case '\n':
|
|
if( zflag )
|
|
{ /* add stin line number of production as a comment */
|
|
printf( "\n%s\t^^\t%d = %d",
|
|
COMMENTSTR, q->stinline, p->in.cst[CEFF] );
|
|
}
|
|
PUTCHAR( *cp );
|
|
continue;
|
|
|
|
case 'Y':
|
|
/* don't check this string: deleted by match */
|
|
continue;
|
|
|
|
case 'Z': /* special machine dependent operations */
|
|
zzzcode( p, &cp, q );
|
|
continue;
|
|
|
|
case 'E': /* exit */
|
|
PUTCHAR( '\n' );
|
|
return;
|
|
|
|
# ifndef STACK
|
|
case 'D': /* test for dependency */
|
|
q1 = getadr( p, &cp );
|
|
if( cp[1] == '!' )
|
|
{
|
|
c=0;
|
|
++cp;
|
|
}
|
|
else c=1;
|
|
q2 = getadr( p, &cp );
|
|
if( q1->tn.op != REG ) cerror( "bad D" );
|
|
if( ushare( q2, q1->tn.rval ) == c ) continue;
|
|
goto cream;
|
|
# endif
|
|
|
|
case 'R': /* put an operand into a particular register */
|
|
/* if the operand is in the register, delete the line */
|
|
v = 0;
|
|
q1 = getadr( p, &cp );
|
|
c = (*++cp == '=');
|
|
if(*(cp + 1) == 'K') {
|
|
v = 1;
|
|
if(typlen(p->tn.type)==8)
|
|
v += 1;
|
|
}
|
|
if(*(cp + 1) == 'J') {
|
|
v = 1;
|
|
if(typlen(p->tn.type)==4)
|
|
v += 1;
|
|
}
|
|
q2 = getadr( p, &cp );
|
|
if( q1->tn.op != REG )
|
|
{
|
|
if( c ) goto cream;
|
|
continue;
|
|
}
|
|
if( q2->tn.op != REG )
|
|
{
|
|
if( c ) goto cream;
|
|
continue;
|
|
}
|
|
if(odebug>1) printf("op1 rval = %d, op2 rval = %d v = %d c = %d\n", q1->tn.rval,q2->tn.rval,v,c);
|
|
if( q1->tn.rval != (q2->tn.rval + v))
|
|
{
|
|
if( c ) goto cream;
|
|
continue;
|
|
}
|
|
if( c ) continue;
|
|
cream:
|
|
/* clobber a line to newline, or up to an E */
|
|
while( *++cp != '\n' && *cp != 'E' )
|
|
{
|
|
if( *cp == '\\' ) ++cp; /* hide next char */
|
|
if( !*cp ) return;
|
|
}
|
|
continue;
|
|
|
|
case 'F': /* this line deleted if FOREFF is active */
|
|
if( goal & FOREFF ) goto cream;
|
|
continue;
|
|
|
|
case 'S': /* field size */
|
|
case 'H': /* field shift */
|
|
case 'M': /* field mask, in place */
|
|
case 'N': /* field mask, right shifted */
|
|
c = *cp;
|
|
if( cp[1] == '~' )
|
|
{
|
|
if( c == 'M' ) c = 'm';
|
|
else if( c == 'N' ) c = 'n';
|
|
else cerror( "bad ~ after S or H" );
|
|
++cp;
|
|
}
|
|
else if( cp[1] == '?' )
|
|
{
|
|
if( c == 'H' ) c = 'h';
|
|
else cerror( "bad ? after S, M, or N" );
|
|
++cp;
|
|
}
|
|
q1 = getadr(p,&cp);
|
|
if( q1->tn.op != FLD ) cerror( "bad FLD for %c", c );
|
|
fldsz = UPKFSZ(q1->tn.rval);
|
|
# ifdef RTOLBYTES
|
|
fldshf = UPKFOFF(q1->tn.rval);
|
|
# else
|
|
t = q1->tn.type;
|
|
if( t & (TLONG|TULONG) )
|
|
{
|
|
fldshf = SZLONG - fldsz - UPKFOFF(q1->tn.rval);
|
|
}
|
|
else if( t & (TSHORT|TUSHORT) )
|
|
{
|
|
fldshf = SZSHORT - fldsz - UPKFOFF(q1->tn.rval);
|
|
}
|
|
else if( t & (TCHAR|TUCHAR) )
|
|
{
|
|
fldshf = SZCHAR - fldsz - UPKFOFF(q1->tn.rval);
|
|
}
|
|
else fldshf = SZINT - fldsz - UPKFOFF(q1->tn.rval);
|
|
# endif
|
|
if( c == 'h' )
|
|
{
|
|
if( fldshf == 0 ) goto cream;
|
|
continue;
|
|
}
|
|
if( c=='S' || c=='H' )
|
|
{
|
|
printf( "%%%x", c=='S' ? fldsz : fldshf );
|
|
continue;
|
|
}
|
|
val = 1;
|
|
val <<= fldsz;
|
|
--val;
|
|
if( c=='M' || c == 'm' ) val <<= fldshf;
|
|
if( c=='m' || c == 'n' ) val = ~val;
|
|
if(*cp == '0' || *cp == '2') {
|
|
if(*cp == '0')
|
|
val >>= 16;
|
|
val &= 0xffff;
|
|
cp++;
|
|
}
|
|
# ifdef MYMASK
|
|
MYMASK(val);
|
|
# else
|
|
printf( "%%%x" , (unsigned short)val );
|
|
# endif
|
|
continue;
|
|
|
|
case 'L': /* output special label field */
|
|
printf( "%d", p->bn.label );
|
|
continue;
|
|
|
|
case 'C': /* for constant value only */
|
|
conput( q1 = getadr( p, &cp ) );
|
|
if( !sideff ) cerror( "constant with side effects?" );
|
|
continue;
|
|
|
|
case 'I': /* in instruction */
|
|
insput( q1 = getadr( p, &cp ) );
|
|
if( sideff ) rmside( q1 );
|
|
continue;
|
|
|
|
case '|': /* output of @SP */
|
|
printf("@SP");
|
|
continue;
|
|
|
|
case 'W': /* output of FP */
|
|
printf("FP");
|
|
continue;
|
|
|
|
case 'A': /* address of */
|
|
adrput( q1 = getadr( p, &cp ) );
|
|
if( sideff ) rmside( q1 );
|
|
continue;
|
|
|
|
case 'G': /* offset of an address */
|
|
q1 = getadr(p, &cp);
|
|
if(q1->tn.op != ICON)
|
|
cerror("G but not address constant");
|
|
if(q1->tn.rval != NONAME && q1->tn.name != (char *)0){
|
|
if(q1->tn.rval < 0 && *(q1->tn.name) == 'L')
|
|
q1->tn.rval = 0xa000;
|
|
else
|
|
q1->tn.rval = 0x2000;
|
|
}
|
|
adrput( q1);
|
|
if( sideff ) rmside( q1 );
|
|
continue;
|
|
|
|
case 'Q': /* offset of an address */
|
|
q1 = getadr(p, &cp);
|
|
if(q1->tn.op != ICON)
|
|
cerror("Q but not address constant");
|
|
if(q1->tn.rval != NONAME && q1->tn.name != (char *)0){
|
|
if(q1->tn.rval < 0 && *(q1->tn.name) == 'L')
|
|
q1->tn.rval = 0x9000;
|
|
else
|
|
q1->tn.rval = 0x1000;
|
|
}
|
|
adrput( q1);
|
|
if( sideff ) rmside( q1 );
|
|
continue;
|
|
|
|
case 'P': /* auto and param offset without FP */
|
|
padrput(q1 = getadr( p, &cp) );
|
|
if( sideff ) rmside( q1 );
|
|
continue;
|
|
|
|
case 'B':
|
|
/* for BA-adressing in ld-operations */
|
|
nadrput( q1 = getadr(p, &cp));
|
|
continue;
|
|
|
|
case 'X':
|
|
/* 'b', 'l' or '\0' - type of operation */
|
|
typ = typlen(p->in.type);
|
|
if(typ == 4)
|
|
PUTCHAR('l');
|
|
else if(p->in.left->tn.op!= REG && typ == 1)
|
|
PUTCHAR('b');
|
|
continue;
|
|
|
|
/* case 'U': /* for upper half of address, only */
|
|
/* upput( q1 = getadr( p, &cp ) ); */
|
|
/* if( sideff ) rmside( q1 ); */
|
|
/* continue; */
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
NODE *
|
|
getlr( p, c )
|
|
NODE *p;
|
|
|
|
{
|
|
|
|
/* return the pointer to the left or right side of p, or p itself,
|
|
** depending on the optype of p
|
|
*/
|
|
|
|
switch( c )
|
|
{
|
|
|
|
case 'K':
|
|
case 'J':
|
|
c = '1' ;
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
return( &resc[c-'1'] );
|
|
|
|
case 'L':
|
|
return( optype( p->in.op ) == LTYPE ? p : p->in.left );
|
|
|
|
case 'R':
|
|
return( optype( p->in.op ) != BITYPE ? p : p->in.right );
|
|
|
|
}
|
|
cerror( "bad getlr: %c", c );
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
NODE *
|
|
getadr( p, pc )
|
|
NODE *p;
|
|
char **pc;
|
|
|
|
{
|
|
/* like getlr, but allows (LL), (LR), etc. */
|
|
int c;
|
|
sideff = 1;
|
|
c = *++(*pc);
|
|
if( c == '-' )
|
|
{
|
|
c = *++(*pc);
|
|
sideff = 0;
|
|
}
|
|
if( c == '.' ) return( p );
|
|
else if( c != '(' ) return( getlr( p, c ) );
|
|
|
|
for(;;)
|
|
{
|
|
switch( c = *++(*pc) )
|
|
{
|
|
|
|
case ')':
|
|
return( p );
|
|
|
|
case 'L':
|
|
p = getl( p );
|
|
continue;
|
|
|
|
case 'R':
|
|
p = getr( p );
|
|
continue;
|
|
|
|
default:
|
|
cerror( "bad table char in (): %c", c );
|
|
}
|
|
}
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
long pow2[] =
|
|
{
|
|
01L, 02L, 04L,
|
|
010L, 020L, 040L,
|
|
0100L, 0200L, 0400L,
|
|
01000L, 02000L, 04000L,
|
|
010000L, 020000L, 040000L,
|
|
0100000L, 0200000L, 0400000L,
|
|
01000000L, 02000000L, 04000000L,
|
|
010000000L, 020000000L, 040000000L,
|
|
0100000000L, 0200000000L, 0400000000L,
|
|
01000000000L, 02000000000L, 04000000000L,
|
|
010000000000L, 020000000000L, 0L,
|
|
};
|
|
|
|
spshape( sh, p )
|
|
NODE *p;
|
|
|
|
{
|
|
long val;
|
|
int t, i;
|
|
|
|
if( !(sh&SPECIAL) ) cerror( "spshape" );
|
|
if( sh&SPTYPE )
|
|
{
|
|
# ifndef NODBG
|
|
if( sdebug )
|
|
printf( "SPTYPE(%d, %o), ttype=%o\n", p-node,
|
|
sh, p->tn.type );
|
|
# endif
|
|
|
|
if( sh & p->tn.type ) return( 1 );
|
|
else return( 0 );
|
|
}
|
|
t = (sh&STMASK);
|
|
i = (sh&SVMASK);
|
|
|
|
switch( t )
|
|
{
|
|
|
|
case SRANGE0:
|
|
case SSRANGE:
|
|
if( i<0 || i>30 ) cerror( "bad shape range" );
|
|
case SVAL:
|
|
case SNVAL:
|
|
case NACON:
|
|
|
|
if( p->tn.op != ICON || p->tn.name != (char *) 0 ) return( 0 );
|
|
if( t == NACON ) return(1);
|
|
val = p->tn.lval;
|
|
if( t==SVAL && val == i ) return( 1 );
|
|
else if( t==SNVAL && val == -i ) return( 1 );
|
|
else if( t==SRANGE0 && val>=0 && val<pow2[i] ) return( 1 );
|
|
else if( t==SSRANGE && val>= -pow2[i] && val<pow2[i] )return(1);
|
|
return( 0 );
|
|
|
|
case SUSER:
|
|
return( special( sh, p ) );
|
|
|
|
default:
|
|
cerror( "bad special call" );
|
|
/* NOTREACHED */
|
|
}
|
|
}
|