365 lines
		
	
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			365 lines
		
	
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include        "ass00.h"
 | 
						|
#include        "assex.h"
 | 
						|
#include        "ip_spec.h"
 | 
						|
 | 
						|
#ifndef NORCSID
 | 
						|
static char rcs_id[] = "$Header$" ;
 | 
						|
static char rcs_ip[] = RCS_IP ;
 | 
						|
#endif
 | 
						|
 | 
						|
short           opt_line ;      /* max_line_no - # lines removed from end
 | 
						|
				   after perfoming exc's.
 | 
						|
				   Used to estimate the distance in # of
 | 
						|
				   instructions.
 | 
						|
				*/
 | 
						|
/*
 | 
						|
** Determine the exact instruction length & format where possible, and the
 | 
						|
** the upper and lower limits otherwise. Enter limits in labeltable
 | 
						|
*/
 | 
						|
pass_3()
 | 
						|
{
 | 
						|
	register line_t *lnp, *rev_lnp;
 | 
						|
	line_t   *tmp_lnp;
 | 
						|
	locl_t   *lbp;
 | 
						|
	int      min_l, max_l, min_bytes;
 | 
						|
	short    last_line ;
 | 
						|
	short    hol_err_line ;
 | 
						|
	register insno ;
 | 
						|
 | 
						|
	pass = 3;
 | 
						|
	opt_line= line_num ; hol_err_line=0 ;
 | 
						|
	min_bytes = max_bytes = 0; rev_lnp= lnp_cast 0 ;
 | 
						|
	for (lnp = pstate.s_fline ; lnp ; opt_line--, line_num-- ) {
 | 
						|
		pstate.s_fline= lnp;
 | 
						|
		insno = ctrunc(lnp->instr_num);
 | 
						|
		switch( insno ) {
 | 
						|
		case sp_fpseu :
 | 
						|
			last_line = line_num ;
 | 
						|
			line_num = lnp->ad.ad_ln.ln_first ;
 | 
						|
			opt_line -= lnp->ad.ad_ln.ln_extra ;
 | 
						|
			lnp->ad.ad_ln.ln_first= last_line ;
 | 
						|
			break ;
 | 
						|
		case sp_ilb1 :
 | 
						|
			lbp = lnp->ad.ad_lp;
 | 
						|
			lbp->l_defined = SEEN;
 | 
						|
			lbp->l_min = min_bytes;
 | 
						|
			lbp->l_max = max_bytes;
 | 
						|
			break ;
 | 
						|
		default:
 | 
						|
		if ( lnp->type1==CONST && (em_flag[insno]&EM_PAR)==PAR_G ) {
 | 
						|
			if (holbase != 0) {
 | 
						|
				if (lnp->ad.ad_i >= holsize) {
 | 
						|
						hol_err_line= line_num ;
 | 
						|
				}
 | 
						|
				lnp->ad.ad_i += holbase;
 | 
						|
			}
 | 
						|
		} else
 | 
						|
		if ( lnp->type1>=VALLOW && (em_flag[insno]&EM_PAR)==PAR_G ) {
 | 
						|
			if (holbase != 0) {
 | 
						|
				pstate.s_fline= lnp->l_next ;
 | 
						|
				newline(CONST) ;
 | 
						|
				pstate.s_fline->instr_num= insno ;
 | 
						|
				pstate.s_fline->ad.ad_i=
 | 
						|
					VAL1(lnp->type1)+holbase ;
 | 
						|
				freearea((area_t)lnp,
 | 
						|
					(unsigned)linesize[VALLOW]) ;
 | 
						|
				lnp= pstate.s_fline ;
 | 
						|
				if ( VAL1(lnp->type1) >= holsize) {
 | 
						|
					hol_err_line= line_num ;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if ( !valid(lnp) ) fatal("Invalid operand") ;
 | 
						|
 | 
						|
		determine_props(lnp, &min_l, &max_l);
 | 
						|
		min_bytes += min_l; max_bytes += max_l;
 | 
						|
		break ;
 | 
						|
		}
 | 
						|
		tmp_lnp= lnp->l_next ;
 | 
						|
		lnp->l_next= rev_lnp ; rev_lnp= lnp ;
 | 
						|
		lnp= tmp_lnp ;
 | 
						|
	}
 | 
						|
	pstate.s_fline= rev_lnp ;
 | 
						|
	if ( hol_err_line ) {
 | 
						|
		line_num= hol_err_line ;
 | 
						|
		werror("address exceeds holsize") ;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
** Determine the format that should be used for each instruction,
 | 
						|
** depending on its offsets
 | 
						|
*/
 | 
						|
 | 
						|
determine_props(lnp, min_len, max_len)
 | 
						|
	line_t *lnp;
 | 
						|
	int    *min_len, *max_len;
 | 
						|
{
 | 
						|
	cons_t  val ;
 | 
						|
	register int insno ;
 | 
						|
	register char *f_off, *l_off ;
 | 
						|
	char defined ;
 | 
						|
 | 
						|
	insno=ctrunc(lnp->instr_num) ;
 | 
						|
	val=parval(lnp,&defined) ;
 | 
						|
	if ( !defined ) {
 | 
						|
		switch(em_flag[insno]&EM_PAR) {
 | 
						|
		case PAR_NO:
 | 
						|
		case PAR_W:
 | 
						|
			f_off = findnop(insno) ;
 | 
						|
			break ;
 | 
						|
		case PAR_G:
 | 
						|
			/* We want the maximum address that is a multiple
 | 
						|
			   of the wordsize.
 | 
						|
			   Assumption: there is no shortie for
 | 
						|
				intr max_word_multiple
 | 
						|
			     where intr is a instruction allowing parameters
 | 
						|
			     that are not a word multiple (PAR_G).
 | 
						|
			*/
 | 
						|
			f_off = findfit(insno, maxadr&(~(wordsize-1))) ;
 | 
						|
			break ;
 | 
						|
		case PAR_B:
 | 
						|
			f_off = findfit(insno, (cons_t)0) ;
 | 
						|
			l_off = findfit(insno, val ) ;
 | 
						|
			if ( f_off != l_off ) {
 | 
						|
				*min_len=oplength(*f_off) ;
 | 
						|
				*max_len=oplength(*l_off) ;
 | 
						|
				lnp->opoff = NO_OFF ;
 | 
						|
				return ;
 | 
						|
			}
 | 
						|
			break ;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		f_off = findfit(insno,val) ;
 | 
						|
	}
 | 
						|
	lnp->opoff = f_off ;
 | 
						|
	*min_len = *max_len = oplength(*f_off) ;
 | 
						|
}
 | 
						|
 | 
						|
char *findfit(instr,val) int instr ; cons_t val ; {
 | 
						|
	register char *currc,*endc ;
 | 
						|
	int found, flags, number ;
 | 
						|
	char *opc ;
 | 
						|
 | 
						|
	endc = opindex[instr+1] ;
 | 
						|
	for ( currc=opindex[instr], found=0 ;
 | 
						|
		!found && currc<endc ; currc++ ) {
 | 
						|
		opc = currc ;
 | 
						|
		flags=ctrunc(*currc++) ;
 | 
						|
		switch ( flags&OPTYPE ) {
 | 
						|
		case OPNO :
 | 
						|
			continue ;
 | 
						|
		case OPMINI :
 | 
						|
		case OPSHORT :
 | 
						|
			number=ctrunc(*++currc) ;
 | 
						|
		}
 | 
						|
		found = opfit(flags, number, val, em_flag[instr]&EM_PAR ) ;
 | 
						|
	}
 | 
						|
	if ( !found ) fatal("Cannot find interpreter opcode") ;
 | 
						|
	return opc ;
 | 
						|
}
 | 
						|
 | 
						|
char *findnop(instr) int instr ; {
 | 
						|
	register char *currc,*endc ;
 | 
						|
 | 
						|
	endc = opindex[instr+1] ;
 | 
						|
	for ( currc=opindex[instr] ; currc<endc ; currc++ ) {
 | 
						|
		switch ( ctrunc(*currc)&OPTYPE ) {
 | 
						|
		case OPNO :
 | 
						|
			return currc ;
 | 
						|
		case OPSHORT :
 | 
						|
		case OPMINI :
 | 
						|
			currc++ ;
 | 
						|
		}
 | 
						|
		currc++ ;
 | 
						|
	}
 | 
						|
	fatal("Cannot find interpreter opcode") ;
 | 
						|
	/* NOTREACHED */
 | 
						|
}
 | 
						|
 | 
						|
int opfit(flag,number,val,i_flag)
 | 
						|
int i_flag,flag,number ; cons_t val ; {
 | 
						|
	/* Number is invalid if flag does not contain MINI or SHORT */
 | 
						|
	switch ( flag&OPRANGE ) {
 | 
						|
	case OP_POS :
 | 
						|
		if ( val<0 ) return 0 ;
 | 
						|
		break ;
 | 
						|
	case OP_NEG :
 | 
						|
		if ( val>=0 ) return 0 ;
 | 
						|
		break ;
 | 
						|
	}
 | 
						|
	if ( flag&OPWORD ) {
 | 
						|
		if ( val%wordsize ) return 0 ;
 | 
						|
		val /= wordsize ;
 | 
						|
	}
 | 
						|
	if ( flag&OPNZ ) {
 | 
						|
		if ( val==0 ) return 0 ;
 | 
						|
		val-- ;
 | 
						|
	}
 | 
						|
	switch ( flag&OPTYPE ) {
 | 
						|
	case OPMINI :
 | 
						|
		if ( val<0 ) val = -1-val ;
 | 
						|
		return val>=0 && val<number ;
 | 
						|
	case OPSHORT :
 | 
						|
		if ( val<0 ) val = -1-val ;
 | 
						|
		return val>=0 && val<number*256 ;
 | 
						|
	case OP16 :
 | 
						|
		if ( i_flag==PAR_G ) return val>=0 && val<=maxadr ;
 | 
						|
		return val>= -32768 && val<=32767 ;
 | 
						|
	case OP32 :
 | 
						|
		return TRUE ;
 | 
						|
	default :
 | 
						|
		fatal("illegal OPTYPE value") ;
 | 
						|
		/* NOTREACHED */
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int oplength(flag) int flag ; {
 | 
						|
	int cnt ;
 | 
						|
 | 
						|
	cnt=1 ;
 | 
						|
	if ( flag&OPESC ) cnt++ ;
 | 
						|
	switch( flag&OPTYPE ) {
 | 
						|
	case OPNO    :
 | 
						|
	case OPMINI  : break ;
 | 
						|
	case OP8     :
 | 
						|
	case OPSHORT : cnt++ ; break ;
 | 
						|
	case OP16    : cnt+=2 ; break ;
 | 
						|
	case OP32    : cnt+=5 ; break ;
 | 
						|
	case OP64    : cnt+=9 ; break ;
 | 
						|
	}
 | 
						|
	return cnt ;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** return estimation of value of parameter
 | 
						|
*/
 | 
						|
cons_t parval(lnp,defined)
 | 
						|
	line_t *lnp;
 | 
						|
	char *defined;
 | 
						|
{
 | 
						|
	register int    type;
 | 
						|
	register locl_t *lbp;
 | 
						|
	register glob_t *gbp;
 | 
						|
	cons_t   offs ;
 | 
						|
 | 
						|
	*defined = TRUE ;
 | 
						|
	type = lnp->type1;
 | 
						|
	switch(type) {
 | 
						|
		default: if ( type>=VALLOW && type<=VALHIGH )
 | 
						|
				 return VAL1(type) ;
 | 
						|
			 error("bad type during parval");
 | 
						|
			 break;
 | 
						|
		case CONST:
 | 
						|
			return(lnp->ad.ad_i);
 | 
						|
		case GLOSYM:
 | 
						|
		case GLOOFF:
 | 
						|
			if ( type!=GLOOFF) {
 | 
						|
				gbp = lnp->ad.ad_gp;
 | 
						|
				offs= 0 ;
 | 
						|
			} else {
 | 
						|
				gbp =lnp->ad.ad_df.df_gp ;
 | 
						|
				offs=lnp->ad.ad_df.df_i ;
 | 
						|
			}
 | 
						|
			if(gbp->g_status&DEF)
 | 
						|
				return(gbp->g_val.g_addr+offs);
 | 
						|
			else {
 | 
						|
				*defined = FALSE ;
 | 
						|
				return offs ;
 | 
						|
			}
 | 
						|
		case LOCSYM:
 | 
						|
			lbp = lnp->ad.ad_lp;
 | 
						|
			switch(pass) {
 | 
						|
			default:error("bad pass in parval");
 | 
						|
			case 3:
 | 
						|
				*defined = FALSE;
 | 
						|
				switch(lbp->l_defined) {
 | 
						|
				default : fatal("Illegal local label") ;
 | 
						|
				case NO :
 | 
						|
					error("Undefined local label") ;
 | 
						|
					lbp->l_defined= NOTPRESENT ;
 | 
						|
				case NOTPRESENT:
 | 
						|
					return max_bytes;
 | 
						|
				case SEEN :
 | 
						|
					return max_bytes - lbp->l_min ;
 | 
						|
				case YES :
 | 
						|
					/* l_min contains line_num
 | 
						|
					   adjusted for exc's.
 | 
						|
					*/
 | 
						|
			return (lbp->l_min - opt_line -1 ) * maxinsl ;
 | 
						|
				}
 | 
						|
			case 4: if(lbp->l_defined == YES)
 | 
						|
					return(lbp->l_min-prog_size-maxinsl);
 | 
						|
				return max_bytes - lbp->l_max- prog_size;
 | 
						|
			case 5: if (lbp->l_defined == YES )
 | 
						|
					return lbp->l_min ;
 | 
						|
				*defined = FALSE ;
 | 
						|
				break ;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		case MISSING:
 | 
						|
			*defined = FALSE ;
 | 
						|
			break;
 | 
						|
		case PROCNAME:
 | 
						|
			return(lnp->ad.ad_pp->p_num);
 | 
						|
	}
 | 
						|
	return(0);
 | 
						|
}
 | 
						|
int valid(lnp) register line_t *lnp ; {
 | 
						|
	cons_t val ;
 | 
						|
	char type ;
 | 
						|
 | 
						|
	type = lnp->type1 ;
 | 
						|
	if ( type>=VALLOW && type<=VALHIGH ) {
 | 
						|
		val= VAL1(type) ;
 | 
						|
		type= CONST ;
 | 
						|
	} else if ( type==CONST ) val = lnp->ad.ad_i ;
 | 
						|
	switch ( em_flag[ctrunc(lnp->instr_num)]&EM_PAR ) {
 | 
						|
	case PAR_NO:
 | 
						|
		return type==MISSING ;
 | 
						|
	case PAR_C:
 | 
						|
		if ( type!=CONST ) return FALSE;
 | 
						|
		if ( val>maxint && val<=maxunsig ) {
 | 
						|
			lnp->ad.ad_i = val -maxunsig -1 ;
 | 
						|
		}
 | 
						|
		return TRUE ;
 | 
						|
	case PAR_D:
 | 
						|
		if ( type!=CONST ) return FALSE;
 | 
						|
		if ( val>maxdint && val<=maxdunsig ) {
 | 
						|
			lnp->ad.ad_i = val -maxdunsig -1 ;
 | 
						|
		}
 | 
						|
		return TRUE ;
 | 
						|
	case PAR_L:
 | 
						|
	case PAR_F:
 | 
						|
		return type==CONST ;
 | 
						|
	case PAR_N:
 | 
						|
		return type==CONST && val>=0 ;
 | 
						|
	case PAR_G:
 | 
						|
		return type==CONST || type==GLOSYM || type==GLOOFF ;
 | 
						|
	case PAR_W:
 | 
						|
		if ( type==MISSING ) return TRUE ;
 | 
						|
	case PAR_S:
 | 
						|
		return type==CONST && val>0 && val%wordsize==0 ;
 | 
						|
	case PAR_Z:
 | 
						|
		return type==CONST && val>=0 && val%wordsize==0 ;
 | 
						|
	case PAR_O:
 | 
						|
		return type==CONST && val>=0 &&
 | 
						|
		    ( val >= wordsize ? val%wordsize : wordsize%val ) == 0 ;
 | 
						|
	case PAR_P:
 | 
						|
		return type==PROCNAME ;
 | 
						|
	case PAR_B:
 | 
						|
		return type==LOCSYM ;
 | 
						|
	case PAR_R:
 | 
						|
		return type==CONST && val>=0 && val<=3 ;
 | 
						|
	default:
 | 
						|
		fatal("Unknown parameter type") ;
 | 
						|
		/* NOTREACHED */
 | 
						|
	}
 | 
						|
}
 |