368 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			368 lines
		
	
	
	
		
			8.2 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 OP16U:
 | |
| 		return val>=0 && val<=65535L &&
 | |
| 		       ( i_flag!=PAR_G || val<=maxadr ) ;
 | |
| 	case OP16 :
 | |
| 		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 OP16U:
 | |
| 	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 */
 | |
| 	}
 | |
| }
 |