(*$M-*)  (***  ASSMCC.PAS -- CONST CONVERSION, EXPR, OPERAND ANALYSIS  ***)
 
 
(*$R-,X+*)
 
(*$L-*)
(*$I+ASSMHD.PAS*)
(*$L+*)
(*******************************************************
	UTILITY PROCEDURES
 *******************************************************)
 
PROCEDURE FINDSYMB  (S:NAME; VAR L:SYMPTR; VAR B:BOOLEAN); EXTERN;
 
PROCEDURE SKIPBLANKS(VAR N : INTEGER);  EXTERN;
 
PROCEDURE LOADSYMB  (VAR N:INTEGER);  EXTERN;
 
PROCEDURE SETERR    (CH:CHAR); EXTERN;

 
(******************************************************
	CONSTANT CONVERSION
 ******************************************************)
 
PROCEDURE CONVERTCONST (VAR N,V,TP : INTEGER);
 
   (* CALLED TO CONVERT STRINGS AND NUMERICS.
 
      CONSTANT TYPES :	HEX     : NNNNH (1ST N IS NUMERIC)
			DECIMAL : NNNNN OR NNNNND (+/- 32767)
			OCTAL   : NNNNNNQ
			BINARY  : NNNNNNNNNNNNNNNNB
			ASCII	: '*','****','''','***''***'
 
      PROCEDURE RETURNS N POINTING PAST CONSTANT
			V = VALUE OF CONSTANT (UNLESS STRING)
			TP= 1 BYTE REF, 2=WORD REF
			STRING = GLOBAL STRING HOLDER		*)
 
 
   VAR   NEG:BOOLEAN;  I,J:INTEGER;
 
   FUNCTION INT(CH:CHAR) : INTEGER;
      BEGIN
      IF CH IN ['A'..'F'] THEN INT := ORD(CH) - ORD('A') + 10
			  ELSE INT := ORD(CH) - ORD('0');
      END;
 
   PROCEDURE ERROR;
      BEGIN
      V := 0; SETERR('N');
      END;
 
   PROCEDURE CHKR(S:CHAR);
      BEGIN
      NEG := TRUE;
      WITH STATEMENTS^ DO
       FOR I := N TO J DO NEG := NEG AND (STMNT[I]>='0') AND (STMNT[I]<=S);
      IF NOT NEG AND PASS1 THEN ERROR
      END;
 
   BEGIN (* CONSTANT CONVERSION -- FIRST CHAR MUST BE NUMERIC OR QUOTE *)
   J := N;  SL := 0;  V := 0;  TP := 1;
   WITH STATEMENTS^ DO
      IF STMNT[N] = '''' THEN   (***  PROCESS ASCII  ***)
	 BEGIN
	 LOOP
	    J := SUCC(J);  
	    EXIT IF (STMNT[J] = '''') AND (STMNT[J+1] <> '''') OR (J+1 = STMLEN) OR (SL=STRLEN);
	    SL := SUCC(SL);  STRING[SL] := STMNT[J];
	    IF (STMNT[J] = '''') AND (STMNT[J+1] = '''') THEN J := SUCC(J);
	    END;
	 IF (STMNT[J]<>'''') THEN SETERR('Q');
	 IF SL=1 THEN V := ORD(STRING[1]);
	 IF SL=2 THEN V := ORD(STRING[1])*256 + ORD(STRING[2]);
	 N := SUCC(J);  (**  POINT PAST QUOTE  **)
	 END
       ELSE  (***  PROCESS NUMERIC  ***)
	 BEGIN
	 WHILE (STMNT[J] IN ['A'..'F','0'..'9']) AND (J<STMLEN) DO J:=SUCC(J);
	 IF (STMNT[J] <> 'H') AND (STMNT[J-1] IN ['B','D']) THEN J := PRED(J);
	 J := PRED(J);   (**  LOOK AT LAST NUMBER IN STRING  *)
	 WHILE (STMNT[N] = '0') AND (N<J) DO N := SUCC(N);
	 CASE STMNT[J+1] OF
	  'H' : IF J-N > 3 THEN ERROR
		ELSE BEGIN
		  NEG := J-N=3;
		  IF NEG THEN
		     BEGIN
		     NEG := STMNT[N] IN ['8','9','A'..'F'];
		     IF NEG THEN  (***  NEGATIVE NUMBER  ***)
		        V := INT(STMNT[N]) - 8
		      ELSE   (*** POSITIVE  ***)
		        V := INT(STMNT[N]);
		     N := N+1;
		     END;
		  FOR I := N TO J DO V := V*16 + INT(STMNT[I]);
		  IF NEG THEN V := -(MAXINT-V) - 1
		  END;  (*   CASE   *)
 
	   OTHERS:   (***  DECIMAL   ***)
		  IF (J-N>4) OR ((J-N=4) AND
			((STMNT[N]>'3') OR ((STMNT[N]='3') AND
			((STMNT[N+1]>'2') OR ((STMNT[N+1]='2') AND
			((STMNT[N+2]>'7') OR ((STMNT[N+2]='7') AND
			((STMNT[N+3]>'6') OR ((STMNT[N+3]='6') AND
			((STMNT[N+4]>'7')))))))))))
		   THEN ERROR
		   ELSE
		     BEGIN
		     CHKR('9');
		     IF NEG THEN
		     FOR I := N TO J DO V := V*10 + INT(STMNT[I]);
		     IF STMNT[J+1] <> 'D' THEN J := PRED(J);
		  END;
 
	   'Q':   (***  OCTAL   ***)
		  IF (J-N>5) OR ((J-N=5) AND (STMNT[N]>'E')) THEN ERROR
		   ELSE
		     BEGIN
		     CHKR('7');
		     IF NEG THEN
			BEGIN
			NEG := ((J-N=5) AND (STMNT[N]='1'));
			IF NEG THEN N := N+1;
			FOR I := N TO J DO V := V*8 + INT(STMNT[I]);
			IF NEG THEN V := -(MAXINT-V) - 1
			END;
		  END;
  
	  'B':    (***  BINARY  ***)
		  IF (J-N>15) THEN ERROR
		   ELSE
		     BEGIN
		     CHKR('1');
		     IF NEG THEN
			BEGIN
			NEG := (J-N=15) AND (STMNT[N]='1');
			IF NEG THEN N := SUCC(N);
			FOR I := N TO J DO V := V*2 + INT(STMNT[I]);
			IF NEG THEN V := -(MAXINT-V) - 1;
			END
		     END
 
	  END;  (***  OF CASES  ***)
 
      N := J+2;
      IF STMNT[N] = 'W' THEN BEGIN TP:=2; N := SUCC(N) END;
      END;   (***  OF NUMERIC   ***)
   END;      (***  OF CONVERT CONSTANT ***)

(******************************************************************
	EVALUATE EXPRESSION
 ******************************************************************)
 
PROCEDURE EVALEXP (VAR N,V:INTEGER; VAR T:OPNDTP; VAR T1:INTEGER);
   
   (* EVALUATE EXPRESSION --
	INPUT:	N POINTS TO START OF EXP IN BUFFER
		EXPRESSION TERMINATED BY CHAR IN EXPTERM OR EOL.
 
	OPERATOR PRECEDENCE:
		8.  ( )  PARENS
		7.  *, /, %(MOD), <-(SHL), ->(SHR)
		6.  +, -
		5.  =, >, >=, <, <=, <> (RELATIONALS)
		4.  -- (LOG NOT)
		3.  &  (LOG AND)
		2.  !  (LOG OR),  # (LOG XOR)
 
	RETURNS	N POINTING AT CHAR PAST EXPR (THE TERMINATOR)
		V CONTAINS VALUE OF EXPRESSION
		T CONTAINS EXPRESSION TYPE
			REG   = REGNAME
			CNST  = CONSTANT EXPRESSION
			FREF  = UNDEFINED EXPRESSION
			OFFS  = OFFSET MEMORY REF EXPR		
		T1 CONTAINS 1 OR 2 FOR BYTE OR WORD REFERENCE TYPE.	*)
 
   CONST DPTH=12;  
 
   TYPE	STACK = RECORD STK:ARRAY[1..DPTH] OF INTEGER; TOP:INTEGER END;
	BITOPS = (ND,LOR,XR,NT,SR,SHL);
	XREFTP = (NOX,PUREX,OPTX);
 
   VAR	OPNSTK,OPRSTK : STACK;
	GLBSTK : ARRAY [1..DPTH] OF RECORD
			GTP : XREFTP;  		(* XTL REF STATUS  *)
			GSN : SYMPTR		(* XTL SYMBOL POINTER *)
			END;
	OP:TWOCHAR;  I,J,V1,V2:INTEGER;  FL,OPNEXP:BOOLEAN;
	S,S1,S2:SYMPTR;	GLTOP:INTEGER;   Z1,Z2:XREFTP;
 
   PROCEDURE BITOP(B1:BITOPS; O1,O2:INTEGER;  VAR O3:INTEGER);
      VAR  BO1,BO2,BO3 : RECORD
		CASE BOOLEAN OF
		  TRUE: (I:INTEGER);
		  FALSE:(B:PACKED ARRAY[0..15] OF BOOLEAN)
		END;
      BEGIN
      BO1.I := O1;  BO2.I := O2;
      FOR J := 0 TO 15 DO
	 CASE B1 OF
	   ND  : BO3.B[J] := BO1.B[J] AND BO2.B[J];
	   LOR : BO3.B[J] := BO1.B[J] OR  BO2.B[J];
	   XR  : BO3.B[J] := (BO1.B[J] AND NOT BO2.B[J]) OR (NOT BO1.B[J] AND BO2.B[J]);
	   NT  : BO3.B[J] := NOT BO1.B[J];
	   SHL : IF J-O2 < 0 THEN BO3.B[J] := FALSE
		 ELSE BO3.B[J] := BO1.B[J-O2];
	   SR  : IF J+O2 > 15 THEN BO3.B[J] := FALSE
		 ELSE BO3.B[J] := BO1.B[J+O2]
	   END;   (***  OF CASE  ***)
 
      O3 := BO3.I;
      END;
 
   PROCEDURE ERRORE(CH:CHAR);
      BEGIN
      SETERR(CH);
      WITH STATEMENTS^ DO
      IF N<STMLEN THEN
       IF NOT (STMNT[N] IN EXPTERM) THEN
        REPEAT N:=SUCC(N) UNTIL (N=STMLEN) OR (STMNT[N] IN EXPTERM);
      END;
 
   PROCEDURE POP (VAR S:STACK; VAR V:INTEGER;  VAR F:BOOLEAN);
      BEGIN
      F := S.TOP = 0;
      IF NOT F  THEN BEGIN V := S.STK[S.TOP];  S.TOP := PRED(S.TOP) END
		ELSE ERRORE('D')
      END;
 
   PROCEDURE POPOP (VAR T:XREFTP; VAR S:SYMPTR; VAR V:INTEGER; VAR F:BOOLEAN);
      BEGIN
      POP (OPNSTK,V,F);
      IF NOT PASS1 THEN
	BEGIN
	S := GLBSTK[GLTOP].GSN;
	T := GLBSTK[GLTOP].GTP;
	GLTOP := PRED(GLTOP);
	END;
      END;
 
   PROCEDURE PUSH (VAR S:STACK; V:INTEGER; VAR F:BOOLEAN);
      BEGIN
      WITH S DO 
	 BEGIN
	 F := TOP=DPTH;
	 IF NOT F THEN BEGIN TOP:=SUCC(TOP); STK[TOP]:=V END
	 	  ELSE ERRORE('D')
	 END
      END;
 
   PROCEDURE PUSHOP (TP:XREFTP; SN:SYMPTR;  V:INTEGER; VAR F:BOOLEAN);
      BEGIN
      PUSH (OPNSTK,V,F);
      IF NOT PASS1 THEN
	BEGIN
	GLTOP := SUCC(GLTOP);
	GLBSTK[GLTOP].GTP := TP;
	GLBSTK[GLTOP].GSN := SN;
	END;
      END;
 
   PROCEDURE NEWXREF(S:SYMPTR; J : INTEGER);	(**  NEW EXTERNAL REFERENCE  **)
      VAR X : XTLPTR;
      BEGIN
      NEW (X);
      IF XREFS = NIL THEN XREFS := X ELSE XLAST^.XNXT := X;
      XLAST := X;
      IF OPNDS = 1 THEN NX1 := X ELSE NX2 := X;
      HASXTL := TRUE;
      WITH X^ DO WITH S^ DO 
	BEGIN
	XN := SNAME;  XA := 0;
	IF J = 8 		 THEN XOP := '+' ELSE XOP := '-';
	IF STYP IN [XTLS,SEGNM]  THEN XTP := 'S' ELSE XTP := 'W';
	XNXT := NIL
	END
      END;
 
   PROCEDURE EXEC;		(**  EXECUTE EXPR OPERATION   **)
      BEGIN
      POPOP(Z1,S1,V1,FL);  IF NOT FL THEN POPOP(Z2,S2,V2,FL);
      POP(OPRSTK,J,FL);
      IF NOT PASS1 THEN
	BEGIN  (*  WORRY ABOUT EXTERNALS  **)
	IF (Z1 <> NOX) OR (Z2 <> NOX) THEN
	   BEGIN
	   IF NOT (J IN [8,9]) THEN SETERR('G');  (** MUST ADD OR SUB  **)
	   IF Z2 = PUREX THEN NEWXREF(S2,8);
	   IF Z1 = PUREX THEN NEWXREF(S1,J);
	   Z1 := OPTX;
	   END
	END;
 
      CASE J OF 	(** OPERATION **)
       1:  ERRORE('P');   (*** UNMATCHED LEFT PAREN ***)
 
       3: (***  * (MUL) ***)
          IF V2 = 0 THEN PUSHOP (Z1,NIL,0,FL)
          ELSE IF ABS(V1) <= ABS(MAXINT/V2) THEN PUSHOP(Z1,NIL,V1*V2,FL)
          ELSE ERRORE('V');
 
       4: (*** / (DIV) ***)
          IF V1 = 0 THEN ERRORE('V')  (* DIV BY 0 *)
          ELSE PUSHOP(Z1,NIL,V2 DIV V1,FL);
     
       5: (*** % (MOD) ***)
          IF V1 = 0 THEN ERRORE('V')  (* DIV BY 0 *)
          ELSE PUSHOP(Z1,NIL,V2 MOD V1,FL);
   
       6: (** <- (LEFT SHIFT) ***)
	  BEGIN BITOP(SHL,V2,V1,J); PUSHOP(Z1,NIL,J,FL) END;
   
       7: (***  -> (RIGHT SHIFT)  ***)
	  BEGIN BITOP(SR,V2,V1,J); PUSHOP(Z1,NIL,J,FL) END;
   
       8: (*** +  (PLUS)   ***)
          IF (V1<0) AND (V2<0) THEN
      	  IF -(MAXINT+V1) <= V2 THEN PUSHOP(Z1,NIL,V1+V2,FL)
      	  ELSE ERRORE('V')
          ELSE IF (V1>0) AND (V2>0) THEN
  	  IF V2 <= MAXINT-V1 THEN PUSHOP(Z1,NIL,V1+V2,FL)
    	  ELSE ERRORE('V')
          ELSE PUSHOP(Z1,NIL,V1+V2,FL);
 
      9:  (***  - (MINUS)  ***)
          IF (V1>0) AND (V2<0) THEN
    	  IF -(MAXINT-V1) <= V2 THEN PUSHOP(Z1,NIL,V2-V1,FL)
    	  ELSE ERRORE('V')
          ELSE IF (V1<0) AND (V2>0) THEN
    	  IF V2 <= MAXINT+V1 THEN PUSHOP(Z1,NIL,V2-V1,FL)
    	  ELSE ERRORE('V')
          ELSE PUSHOP(Z1,NIL,V2-V1,FL);
 
     10:  (***  = (EQUAL)  ***)
          PUSHOP(Z1,NIL,ORD(V1=V2),FL);
 
     11:  (***  < (LESS THAN) ***)
          PUSHOP(Z1,NIL,ORD(V2<V1),FL);
 
     12:  (***  <=  (LESS EQUAL)  ***)
          PUSHOP(Z1,NIL,ORD(V2<=V1),FL);
 
     13:  (*** >  (GREATER)  ***)
          PUSHOP (Z1,NIL,ORD(V2>V1),FL);
   
     14:  (***  >= (GREATER OR EQUAL)  ***)
          PUSHOP (Z1,NIL,ORD(V2>=V1),FL);
 
     15:  (***  <>  (NOT EQUAL)   ***)
          PUSHOP (Z1,NIL,ORD(V2<>V1),FL);
 
     16:  (*** -- (LOG NOT)   ***)
	  BEGIN BITOP(NT,V1,V1,J); PUSHOP(Z1,NIL,J,FL) END;
 
     17:  (***  & (LOG AND)   ***)
	  BEGIN BITOP(ND,V2,V1,J); PUSHOP(Z1,NIL,J,FL) END;
 
     18:  (***  ! ( LOG OR)   ***)
	  BEGIN BITOP(LOR,V2,V1,J); PUSHOP(Z1,NIL,J,FL) END;
 
     19:  (***  # (LOG XOR)   ***)
	  BEGIN BITOP(XR,V2,V1,J); PUSHOP(Z1,NIL,J,FL) END
 
    END;  (*  OF CASES  *)
    END;  (*  OF EXEC   *)
 
   BEGIN
   OPNSTK.TOP := 0;  OPRSTK.TOP := 0;  V := 0;  T := CNST;  OPNEXP := TRUE;
   T1 := 0;  SL:=0;  GLTOP := 0;       Z1 := NOX;;
   WITH STATEMENTS^ DO
   LOOP
      SKIPBLANKS(N);
      EXIT IF (N=STMLEN) OR (STMNT[N] IN EXPTERM) OR (T=REG);
      IF STMNT[N] IN OP1 THEN
	 BEGIN  (*  OPERATOR  *)
	 OP[1] := STMNT[N];  N := SUCC(N);
	 IF STMNT[N] IN OP2 
	   THEN BEGIN  OP[2] := STMNT[N];  N := SUCC(N) END
	   ELSE OP[2] := ' ';
	 I := 1;
	 WHILE (EXOPS[I].OPTR <> OP) AND (I<=OPNO) DO I := SUCC(I);
	 IF OPNO < I THEN ERRORE('O') ELSE
	    BEGIN
	    IF OPNEXP AND (I<>1) THEN  (*  OPERAND WAS EXPECTED -- UNARY OP ??  *)
	       IF I IN [8,9,16] (** PLUS, MINUS, NOT **)
		  THEN PUSHOP(Z1,NIL,0,FL)
		  ELSE ERRORE('E');
	    OPNEXP := TRUE;
	    WITH OPRSTK DO 
	       BEGIN
	       LOOP
		  FL := TOP=0;
		  IF NOT FL THEN FL:= (EXOPS[STK[TOP]].OPREC < EXOPS[I].OPREC)  OR
				 ((STK[TOP]=1) AND (I=2))  OR (I=1);
		  EXIT IF FL;
		  EXEC;
		  END;
	       IF I=2   (*** CURRENT OPERATOR IS RIGHT PAREN  ***)
		THEN IF TOP>0
			THEN IF STK[TOP] = 1  (***  LEFT PAREN  ***)
				THEN BEGIN POP(OPRSTK,V1,FL); OPNEXP:=FALSE END
				ELSE ERRORE('P')
			ELSE ERRORE('P')
		ELSE PUSH(OPRSTK,I,FL);
	       END  	(***  OF WITH  ***)
	    END;	(**  OF NOT ERROR  *)
	 END
      ELSE  (***   PROCESS OPERAND   ***)
	 IF NOT OPNEXP THEN ERRORE('E') ELSE
	 BEGIN
	 IF STMNT[N] IN ['0'..'9',''''] THEN
	    BEGIN  (*** LOAD CONSTANT ***)
	    CONVERTCONST(N,V1,I);
	    PUSHOP(NOX,NIL,V1,FL);
	    IF I=2 THEN T1 := 2
		   ELSE IF T1<2 THEN T1 := I;
	    END
	 ELSE IF STMNT[N] IN ['$','@','A'..'Z'] THEN
	    BEGIN (*** LOAD SYMBOL ***)
	    LOADSYMB(N);
	    FINDSYMB(GSYM,S,FL);
	    IF NOT FL THEN BEGIN PUSHOP(NOX,NIL,0,FL); T := FREF END
	    ELSE IF S^.STYP=REGNM THEN BEGIN T:=REG; V:=S^.SVAL END
	    ELSE IF S^.STYP IN [SEGNM,XTLS] THEN
		BEGIN
		T := SGNM;  V := 0;
		IF NOT PASS1 THEN NEWXREF(S,8)
		END
	    ELSE BEGIN
		 IF (S^.STYP IN [MEMR,MBYTE,MWORD,XTLB,XTLW]) AND (T<>FREF) THEN
		    BEGIN
		    T := OFFS;
		    IF S^.STYP IN [XTLW,MWORD]  THEN T1 := 2 
						ELSE IF T1<2 THEN T1 := 1
		    END;
		 IF S^.STYP = PERW THEN T1 := 2;
		 IF (S^.STYP = PERM) AND (T1<2) THEN T1 := 1;
		 IF GSYM='$     ' THEN V1:=ADDR ELSE V1:=S^.SVAL;
		 IF S^.STYP IN [XTLB,XTLW] THEN Z1 := PUREX ELSE Z1 := NOX;
		 PUSHOP (Z1,S,V1,FL)
		 END
	    END
	 ELSE  ERRORE('E');
	 OPNEXP := FALSE;
	 END
      END ;  (*** OF LOOP  ***)
 
   IF OPNEXP THEN ERRORE('E')
     ELSE FOR I := 1 TO OPRSTK.TOP DO EXEC;  (***  CLEAR STACK  ***)
 
   IF NOT (T IN [REG,SGNM]) THEN
      BEGIN
      V := OPNSTK.STK[1];
      IF (GLBSTK[1].GTP=PUREX) AND NOT PASS1 THEN NEWXREF(GLBSTK[1].GSN,8)
      END
 
   END;   (***  OF EVAL EXP  ***)

(*****************************************************
	EVALUATE OPERAND
 *****************************************************)
 
PROCEDURE EVALOPND (VAR N : INTEGER;  VAR O : OPERAND);
 
   (* EVALUATE OPERAND POINTED AT BY N.
      OPERAND TYPES	FORM		RETURNED VALS
	REGNM		REG NAME	REG NUMBER
	CONSTANT	CONST EXPR	CONSTANT VALUE
	OFFSET		ADDR EXP	ADDR VALUE
	IND BASE	[BR].ADDREXP	BR,ADDR VALUE
	IND INDEX	ADDREXP[XR]	XR,ADDR VALUE
	IND B/X		[BR].ADDREXP[XR] BR,XR,ADDR VALUE
      RETURNS
	N POINTING AT CHAR PAST OPERAND (';',',', OR EOL)
	O CONTAINS OPERAND DESCRIPTION.			*)
 
   VAR J,EV,CTP : INTEGER;  TP:OPNDTP;  OK:BOOLEAN;
 
   FUNCTION BW(I:INTEGER):INTEGER;
      VAR K:INTEGER;
      BEGIN
      IF (I>127) OR (I<-128) THEN K:=3
      ELSE IF (I<>0) THEN K:=2
	   ELSE K := 1;
      BW := K 
      END;
 
   BEGIN
   SKIPBLANKS(N);
   OPNDS := SUCC(OPNDS);
   IF OPNDS = 1 THEN NX1 := XD;
   IF (OPNDS=2) AND (NX1=XD) THEN OPNDS := 1;   (* NO XTL IN FIRST OPERAND *)
   WITH STATEMENTS^ DO WITH O DO
      BEGIN
      OK := TRUE;  OPTP := CNST;  OPLN := 1; OPV := 0;
      
      (***  FIRST LOOK FOR SEGMENT DESCRIPTOR  'SR:'  ***)
      J := N;  OSR := 0;  ISEGJ := FALSE;
      WHILE (J<STMLEN) AND NOT (STMNT[J] IN (EXPTERM OR [':',''''])) DO J:=SUCC(J);
      IF STMNT[J] = ':' THEN  (*** THERE IS SEGMENT DESCRIPTOR ***)
	 BEGIN
	 EVALEXP(N,EV,TP,J);   N := SUCC(N);  (*** GET PAST : ***)
	 SKIPBLANKS(N);
	 IF ((ST=JMP) OR (ST=CALL)) AND ((TP IN [CNST,SGNM])  (** INTERSEGMENT JMP **)
		OR (PASS1 AND (TP=FREF))) THEN 
	    BEGIN
	    ISEGD:=EV;  ISEGJ:=TRUE;  OPNDS:=2;  NX2:=NX1 
	    END
	 ELSE IF (TP <> REG) THEN SETERR('R') ELSE
	 IF      EV = 17 THEN OSR := 56B
	 ELSE IF EV = 16 THEN OSR := 46B
	 ELSE IF EV = 18 THEN OSR := 66B
	 ELSE IF EV = 19 THEN OSR := 76B
	 ELSE SETERR('R') 
	 END;
 
      (***  LOOK FOR INDIRECT BASE REG  ***)
      IF STMNT[N] = '[' THEN (*** INDIRECT BASE REG IS SPECIFIED ***)
	 BEGIN
	 N := SUCC(N); SKIPBLANKS(N); LOADSYMB(N);
	 SKIPBLANKS(N); 
	 OK := OK AND (STMNT[N]=']');
	 N := SUCC(N);
	 SKIPBLANKS(N);  OK := OK AND (STMNT[N]='.');
	 IF OK THEN
	    BEGIN
	    OPTP := INDB;   RB := 0;  N := SUCC(N);
	    IF GSYM = 'BP    ' THEN RB := 5
	    ELSE IF GSYM = 'BX    ' THEN RB := 3
		 ELSE SETERR('R')
	    END
	 END
      ELSE RB := 0;
 
      (***  FIND EXPRESSION PART  ***)
      EVALEXP(N,EV,TP,OTP);
      CASE TP OF
	CNST: BEGIN OPV := EV;  OPLN:=BW(EV);  CTP := OTP;
		    IF EV=0 THEN OPLN:=2;  OTP:=OPLN-1
		    END;
	REG : IF (OPTP<>CNST) OR (OSR<>0) THEN SETERR('R')
	      ELSE BEGIN OPTP:=REG; OPV:=EV;
		   IF EV IN [8..15] THEN OTP:=1
				    ELSE OTP:=2;
		   OPLN := 1;
		   END;
	OFFS: BEGIN
	      OPLN:=3;  OPV := EV;
	      IF OPTP = CNST THEN OPTP := OFFS ELSE OPLN:=BW(OPV);
	      END;
	FREF: BEGIN
	      OPTP := FREF;
	      IF NOT PASS1 THEN SETERR('U');
	      OPLN := 3;  OTP := 1;  (* ASSUME WORST CASE *)
	      END
	END;   (***   OF CASES   ***)
 
      (***  LOOK FOR INDEX REG   ***)
      IF STMNT[N] = '[' THEN
	 BEGIN
	 N := SUCC(N); SKIPBLANKS(N); LOADSYMB(N); SKIPBLANKS(N);
	 OK := OK AND (STMNT[N]=']');
	 N := SUCC(N);  SKIPBLANKS(N);
	 IF OK THEN
	    BEGIN
	    IF OPTP=REG THEN SETERR('R')
	    ELSE IF OPTP<>FREF THEN
	    IF OPTP = INDB THEN OPTP:=INDBX 
			   ELSE BEGIN OPTP:=INDX; OPLN:=BW(OPV) END;
	    IF TP = CNST THEN OTP := CTP;
	    IF GSYM='SI    ' THEN RX := 6
	    ELSE IF GSYM='DI    ' THEN RX := 7
	    ELSE IF (GSYM='BX    ') AND (RB=0) THEN RX:=3
		 ELSE BEGIN SETERR('R'); RX := 0 END
	    END
	 ELSE RX := 0
	 END
      ELSE RX := 0;   IF NOT OK THEN SETERR('A');
      END;  (***  OF WITH  ***)
   IF OPNDS = 1 THEN NX2 := NX1
   END   (***   OF OPERAND EVALUATION   ***)	.
