Google
 

Trailing-Edge - PDP-10 Archives - ALGOL-20_1-29-82 - algol-sources/algcod.mac
There are 8 other files named algcod.mac in the archive. Click here to see a list.
;
;
;COPYRIGHT (C) 1975,1981,1982 BY
;DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
;
;
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
;ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH LICENSE AND WITH THE
;INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR ANY  OTHER
;COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
;OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF THE  SOFTWARE  IS  HEREBY
;TRANSFERRED.
;
;THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT  NOTICE
;AND  SHOULD  NOT  BE  CONSTRUED  AS A COMMITMENT BY DIGITAL EQUIPMENT
;CORPORATION.
;
;DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY  OF  ITS
;SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
;
;
;SUBTTL CODE GENERATION ROUTINES PART 1

; WRITTEN BY H. VAN ZOEREN, C.M.U.
; EDITED BY R. M. DE MORGAN AND Andrew J. Skinner

	HISEG

	SEARCH ALGPRM,ALGMAC	; SEARCH PARAMETER FILES
	MODULE MCOD;
	$PLEVEL=2;
BEGIN

EXPROC CHECKARITH
EXPROC CLOSE
EXPROC COMBASSIGN
EXPROC COMBLEX
EXPROC CONVERT
EXPROC EMITCODE
EXPROC ERRLEX
EXPROC FAIL
EXPROC GLOAD
EXPROC IPLUNK
EXPROC LOAD
EXPROC MARRY
EXPROC MERGEPORTIONS
EXPROC PLUNK
EXPROC REOPEN
EXPROC REVORDER
EXPROC SETUP
EXPROC STOCON
EXPROC TOCT1
EXPROC TOCT2

EXTERN CTILR,CTLRI,CTLRR	;COMPILE-TIME CONVERSION SR'S;
EXTERN POWC1,POWC2,POWC3			;COMPILE-TIME POWER SR'S;

INTERN OPUMIN,OPABS,OPENT1,OPENT2,OPENT3,OPJSPX,OPMVMS	; OPS USED IN CGFUN
INTERN OPPSJP,OPSGN1,OPSGN2,OPSGN3,OPSETO
INTERN OPADDB,OPAOS,OPSOS,OPMVSM
INTERN OPJMPE,OPJMPG,OPJRST,OPMVLP
INTERN OPCONC,OPCONV,OPMOVE,OPABS1,OPLNEG
INTERN OPENT4,OPENT5,KIOPS

; * * * * TABLE OF INSTRUCTIONS (ACTUAL AND PSEUDO)
;	    TO BE GENERATED IN CGEN AND CGFUN

OPCODE:
OPPOW:	POWR1	0,$R !7		; 3 BY 4 TABLE OF "^" SUBROUTINES
	POWR4	0,$R !0		;
	POWR5	0,$LR!0		;
OPTDZA:	TDZA				; USED IN RELATIONS
	POWR2	0,$R !7		;
	POWR4	0,$R !1		;
	POWR5	0,$LR!1		;
OPSETO:	SETO				; USED IN RELATIONS
	POWR3	0,$LR!7		;
	POWR5	0,$LR!2		;
	POWR5	0,$LR!3		;

OPTIMES:IMUL			; INTEGER "*"
	FMPR			; REAL "*"
	LFMP			; LONG REAL "*" (PSEUDO OPN)
	DFMP	A0,A3

OPDIV:	IDIV			; INTEGER "DIV"
OPSLASH:NOOP
OPREM:	FDVR			; REAL "/"
	LFDV			; LONG REAL "/" (PSEUDO OPN)
	DFDV	A0,A3
	RLFDV			; REVERSED LONG REAL "/" (PSEUDO OPN)

OPUMIN:	MOVN			; INTEGER NEGATE
OPUPLUS:MOVN			; REAL NEGATE
OPLNEG:	LMOVN	0,0		; LONG REAL NEGATE PSEUDO-OP
OPPLUS:	ADD			; INTEGER "+"
	FADR			; REAL "+"
	LFAD			; LONG REAL "+" (PSEUDO OPN)
	DFAD	A0,A3		; LFADC

OPMINUS:SUB			; INTEGER "-"
OPFSBR:	FSBR			; REAL "-"
OPLFSB:	LFSB			; LONG REAL "-" (PSEUDO OPN)
	DFSB	A0,A3
	RLFSB			; REVERSED LONG REAL "-" (PSEUDO OPN)
OPLSS:	CAML			; INTEGER OR REAL "<"
	CAIL			; LONG REAL "<"
OPGTR:	CAMG			; ">" (AND REVERSED "<")
	CAIG
OPRGTR:	CAML			;   REVERSED ">"
	CAIL

OPLEQ:	CAMLE			; INTEGER OR REAL "<="
	CAILE			; LONG REAL "<="
OPGTE:	CAMGE			; ">=" (AND REVERSED "<=")
	CAIGE
OPRGTE:	CAMLE			;   REVERSED ">="
	CAILE

OPEQ:	CAME			; INTEGER OR REAL "="
	CAIE			; LONG REAL "="
OPNE:	CAMN			; INTEGER OR REAL "#"
	CAIN			; LONG REAL "#"

OPNOT:	SETCM			; BOOLEAN "NOT"
OPAND:	AND			; BOOLEAN "AND"
OPOR:	OR			; BOOLEAN "OR"
OPIMP:	ORCA			; BOOLEAN "IMP"
OPEQV:	EQV			; BOOLEAN "EQV"
OPRIMP:	ORCM			; REVERSED "IMP"

OPASS:	MOVEM			; INTEGER ":="
	MOVEM			; REAL ":="
	LMOVEM			; LONG REAL ":=" (PSEUDO OPN)
	LMOVEM			; STRING ":=" (PSEUDO OPN)
OPTCSF:	TCSF			; FORMAL ":=" (PSEUDO OPN)

OPCONV:	CIR			; 3 BY 4 TABLE OF CONVERSION CALLS
	CIL			;
OPPUSH:	PUSH				; USED IN "^"CALL
	CRI			;
OPMVI1:	MOVEI	1,0			; USED IN "^" CALL
	CRL			;
OPLPSH:	LPUSH				; LONG REAL PUSH PSEUDO (USED IN "^" CALL)
	CLI			;
	CLR			;
OPJSPX:	ELI			; LONG ENTIER
OPMOVE:	MOVE			; INTEGER MOVE
	MOVE			; REAL MOVE
	LMOVE			; LONG REAL MOVE (PSEUDO OPN)

OPCONC:	FLTR	A0,A0		; 3 BY 4 TABLE OF COMPILE-TIME
	PUSHJ	SP,CTILR	;   CONVERSIONS FOR CONSTANTS
OPPSJP:	PUSHJ	SP,0		; USED TO CALL LIBRARY FUNCTIONS
	FIXR	A0,A0		;
OPABS:	MOVM			; IN-LINE "ABS"
	SETZ	A1,		;
OPMVMS:	MOVM	0,(SYM)		; CONSTANT TO LOAD ABS(SYM)
	PUSHJ	SP,CTLRI	;
	PUSHJ	SP,CTLRR	;
OPABS1:					;..AND IN .CGFTEST (ALGFUN)
	EXP	<JUMPGE 0,2>!$RA_22	;USED IN IN-LINE LONG "ABS"

OPPOWC:	PUSHJ	SP,POWC1	; COMPILE-TIME INTEGER "^" INTEGER
	PUSHJ	SP,POWC2	; COMPILE-TIME REAL "^" INTEGER
	PUSHJ	SP,POWC3	; COMPILE-TIME LONG REAL "^" INTEGER

OPMVLP:	MOVE	0,(LOP)			; CONSTANT FOR GLOAD OF LOP
OPMVSM:	MOVE	0,(SYM)			; CONSTANT FOR GLOAD OF SYM

OPENT1:	MULI	0,400			; IN-LINE REAL "ENTIER"
OPENT2:	TSC
OPENT3:	EXP	<ASH 0,-243>!$NEXT_22

OPSGN1:	EXP	<JUMPE 0,3>!$RA_22	; IN-LINE "SIGN"
OPSGN2:	ASH	0,-43
OPSGN3:	IORI	0,1

OPADDB:	ADDB				; USED IN "FOR" INCREMENT
	FADRB
OPAOS:	AOS
OPSOS:	SOS

OPJMPE:	JUMPE				; USED IN "FOR" TEST
OPJMPG:	JUMPG
OPJRST:	JRST

OPBYT3:	EXP	<DPB 0,0>!$ACC_22
OPSTRA:	TCADDF	STRASS			; CALL ON STRING ASSIGNMENT

OPCMPR:	TCADDF	COMPAR			; CALL ON STRING COMPARE SR
OPSTZB:	SETZB	0,(LOP)			; ASSIGN A ZERO
OPSTOB:	SETOB	0,(LOP)			; ASSIGN ALL ONES
OPASHL:	ASH	0,21			; MULTIPLY BY POWER OF 2
OPASHR:	ASH	0,-21			; DIVIDE BY POWER OF 2
OPENT4:	FSBRI	0,(0.5)		; IN LINE ENTIER FOR KI10

OPENT5:	FIXR	0,0

;	REAL KI10 OPERATORS

KIOPS:	DMOVE			; 700
	DPUSH
	DMOVEM
	TCTHEN
	TCELSE
	TCFI
	TCTO
	TCOT
	DMOVN				; 710
	TCTYDES
	DMOVNM
	TCSF
	DMOVEM
	715
	DFAD
	DFSB
	DFMP			; 720
	DFDV
	SUBTTL	CODE GENERATION ROUTINES	* CGASS *

PROCEDURE CGASS

	;..GENERATE CODE TO PERFORM AN ASSIGNMENT;
	    ;  ON ENTRY, LEXEME FOR RIGHT HAND SIDE IS IN SYM
	    ;  LEXEME FOR LEFT PART IS IN LOP
	;  IF TYPES ARE ARITHMETIC AND DO NOT MATCH, SYM WILL BE
	    ;  CONVERTED TO THE TYPE OF LOP.
	;  SPECIAL CASES FOR NON-FORMAL ASSIGNMENTS:
	    ;  LOP _ 0		("SETZB" GENERATED)
	    ;  LOP _ -1		("SETOB" GENERATED)
	;  RESULT IS A CLOSED PORTION WHOSE LEXEME IS IN SYM;

BEGIN
OWN CGATMP;		;..TEMPORARY TO HOLD LOP FOR FORMALS;
 IF LOP IS AN ERROR LEXEME
				JUMPGE	LOP,FALSE;$
 THEN;..SET RESULT LEXEME AND LEAVE;
   ERRLEX;
 ELSE;..NO ERRORS YET ..... GO ON;
 BEGIN
  ;..SET REV OFF;
				MOVNI	REV,SYM;$
  ;..INITIALIZE OP TO "_" (NEEDED IN REVORDER);
				MOVE	T,ZASS;$
				MOVEM	T,OP;$
  IF LOP<TYPE> NEQ SYM<TYPE>
				F.TYPE	(T3,LOP);
				F.TYPE	(T4,SYM);
				CAMN	T3,T4;$
				GOTO	FALSE;$
  THEN;..TYPES DO NOT MATCH;
    BEGIN
      IF LOP<TYPE> = ARITH AND SYM<TYPE> = ARITH
				TLNN	LOP,$ARC;$
				T.ARITH	(SYM);
      THEN;..UNMATCHED ARITHMETIC TYPES;
	;..CONVERT SYM TO THE TYPE OF LOP;
				MOVE	T,T3;$
	  CONVERT;
      ELSE;..TYPES ARE NOT BOTH ARITHMETIC;
	IF LOP<TYPE>=STRING!REGULAR
				T.S	(LOP);
				T.REG	(LOP);
	THEN;..BYTE ASSIGNMENT;
	  BEGIN
	    IF SYM<TYPE> = ARITHMETIC
				T.ARITH	(SYM);
	    THEN;..BYTE IS ARITHMETIC;
	      BEGIN
		IF SYM<TYPE> NEQ INTEGER
				TN.I	(SYM);
		THEN;..BYTE OPERAND MUST BE CONVERTED TO INTEGER;
		  ;..CONVERT SYM TO INTEGER TYPE;
				MOVEI	T,$I;$
		    CONVERT;
		FI
	      ENDD
	    ELSE;..ERROR -- MISMATCHED TYPES;
	      ;GO TO WRITE FAIL MESSAGE AND DIE;
				GOTO	LCGAS3;$
	    FI
	  ENDD
	ELSE;..TYPES CANNOT BE MATCHED;
	  BEGIN
	    LCGAS3:
	    FAIL(65,FRIED,SYM,UNMATCHED TYPE CLASSES FOR AN ASSIGNMENT);
	    ;GO TO LAST "ENDD";
				GOTO	LCGAS1;$
	  ENDD
        FI
      FI
    ENDD
  ELSE
    IF LOP<TYPE!STATUS>=STRING!REGULAR
				T.S	(LOP);
				T.REG	(LOP);
    THEN
      ;..STRING ASSIGNED TO A BYTE POINTER, GO TO WRITE
      ;..FAIL MESSAGE AND DIE;
				GOTO	LCGAS3;$
    FI
  FI;
EDIT(044); Dont force constants to D.P. unnecessarily
  IF SYM = PSEUDO-LONG REAL CONSTANT			; [E044]
				TLNN	SYM,$TYPE-$LR	; [E044]
				T.CONST	(SYM)		; [E044]
				TLNE	SYM,$CT-$IMM	; [E044]
				TLNN	SYM,$DEC	; [E044]
				GOTO	FALSE		; [E044]
				F.LOCN	(T2,SYM)	; [E044]
				ADD	T2,CONTAB	; [E044]
				SKIPL	T4,3(T2)	; [E044]
				GOTO	FALSE		; [E044]
  THEN;..CONVERT SYM TO A GENUINE LONG REAL CONSTANT	; [E044]
				MOVE	T3,2(T2)	; [E044]
				TLZ	T4,(1B0)	; [E044]
				TOCT	(2,SYM)		; [E044]
  FI							; [E044]
  IF LOP = FORMAL BY NAME
				T.FON	(LOP);
  THEN;..ASSIGNMENT TO A FORMAL;
    BEGIN
      ;..THE THUNK FOR STORING INTO A FORMAL NEEDS THE RIGHT-HAND
      ;  VALUE IN A0 AND THE FORMAL IN A2;
      IF SYM IS A POINTER
				T.PTR	(SYM);
      THEN;..PUT ITS VALUE INTO AC0;
				GOTO	LCGAS2;$
      FI
      IF VALUE OF SYM NOT IN AC0
				TN.AC0	(SYM);
      THEN;..PUT IT IN;
	LCGAS2:
	LOAD(SYM,A0);
      FI
      ;..SAVE LOP (LEXEME FOR FORMAL SYMBOL);
				MOVEM	LOP,CGATMP;$
      ;..FOOL MERGEPORTIONS. TELL IT THAT LOP IS AN INT. EXP. (IN A2);
				TLZ	LOP,$KIND!$TYPE!$STATUS!$AM;$
				TLO	LOP,$EXP!$I!$SIM!$ACC;$
				HRRI	LOP,A2;$
      MERGEPORTIONS;
      IF LOP IS IN THE STACK OR LOP<RHS>#A2
				TLNN	LOP,$STACK;$
				GOTO	TRUE;$
				MOVEI	LOP,(LOP);$
				CAIN	LOP,A2;$
				GOTO	FALSE;$
      THEN;..MERGEPORTIONS DID IT BECAUSE OF ACC CONFLICT;
	;..GET LOP BACK INTO A2 (NO CONFLICT POSSIBLE NOW);
	;PLUNK(MOVE,A2,LOP);
				MOVE	T,OPMOVE;$
				MOVEI	T1,A2;$
				PLUNK	(LOP);
      FI
      ;..RESTORE ORIGINAL LOP LEXEME;
				MOVE	LOP,CGATMP;$
      ;..EXECUTE THUNK (F[1]);
      ;PLUNK(TCSF,LOP);
      ;..TCSF IS A PSEUDO TO GENERATE THE XCT TO STORE INTO A FORMAL;
				MOVE	T,OPTCSF;$
				PLUNKI	(LOP);
    ENDD
  ELSE;..NON-FORMAL ASSIGNMENT;
    BEGIN
      IF SYM IS A POINTER
				T.PTR	(SYM);
      THEN;..LOAD VALUE OF SYM INTO SAME ACC USED BY PTR;
				F.LOCN	(T2,SYM);
	LOAD(SYM,@T2);
      ELSE;..SYM IS NOT A POINTER;
        IF SYM = SINGLE
				T.SINGLE(SYM);
        THEN;..THE VALUE OF SYM IS NOT YET IN AN ACC;
	  BEGIN
	    IF LOP<TYPE> NEQ STRING
				TLNN	LOP,$TYPE-$S;$
				GOTO	FALSE;$
	    THEN;..CHECK FOR SPECIAL CASES (SYM = 0 OR -1);
	      BEGIN
	        IF SYM = IMMEDIATE AND SYM<VALUE> = 0
				TRNN	SYM,777777;$
				T.IMM	(SYM);
	        THEN;..STORE A ZERO;
	          BEGIN
		    ;..GENERATE SETZB TO STORE ZERO IN LOP AND INTO A FREE ACC;
				MOVE	T1,OPSTZB;$
		    ;..GO AND GENERATE THE STORE INSTRUCTION;
				GOTO	LCGAS5;$
	          ENDD
	        FI
	        IF SYM IS A ONE WORD CONSTANT = -1 (ALL ONES)
				TLNE	SYM,$CT-$IMM;$
				TLNE	SYM,$VAR1!$CONST;$
				GOTO	FALSE;$
				F.LOCN	(T,SYM);
				ADD	T,CONTAB;$
				SETCM	T,1(T);$
				JUMPN	T,FALSE;$
	        THEN;..STORE ALL ONES;
	          BEGIN
		    ;..GENERATE SETOB TO STORE ONES IN LOP AND AN ACC;
				MOVE	T1,OPSTOB;$
		    LCGAS5:
		    ;..EMIT SETB COMMAND;
				HRRI	T1,ANYAC;$
				PUSHJ	SP,.LOAD;$
		    ;LEX(SYM) _ (EXPR,SAME,SIMPLE,LOP<LOCN>);
				TLZ	SYM,$KIND!$STATUS!$AM;$
				TLO	SYM,$EXP!$SIM!$ACC;$
				HRR	SYM,LOP;$
		    REOPEN(LOP);
		    ;..GO OUT TO COMBINE LEXEMES;
				GOTO	LCGAS4;$
	          ENDD
	        FI
	      ENDD
	    FI
	    ;..GET THE VALUE OF SYM INTO A FREE ACC;
	      LOAD(SYM,ANYAC);
	  ENDD
	FI
      FI
      IF LOP = BYTE POINTER
				HLRZ	T,LOP;$
				CAIE	T,$VAR!$S!$REG!$DECL!$PTR;$
				GOTO	FALSE;$
      THEN;..SET SWITCH ON;
				SETOM	0,CGATMP;$
      ELSE;..SET SWITCH OFF;
				SETZM	0,CGATMP;$
      FI
      IF LOP = SINGLE
				T.SINGLE(LOP);
      THEN;..NO PORTION NECESSARY FOR LOP;
	REOPEN(SYM);
      ELSE;..BOTH LOP AND SYM ARE PORTIONS;
	BEGIN
	  REVORDER;
	  MERGEPORTIONS;
	  IF REV
				T.REV;
	  THEN;..PORTIONS WERE REVERSED;
	    BEGIN
	      ;..RE-EXCHANGE LEXEMES;
				EXCH	LOP,SYM;$
	      ;..SET REV OFF;
				MOVNI	REV,SYM;$
	    ENDD
	  FI
	  IF SYM IS IN THE STACK
				T.STK	(SYM);
	  THEN;..VALUE WAS PUSHED DUE TO ACC CONFLICT;
	    ;..PUT IT BACK IN AN ACC;
				MOVE	T,OPMVSM;$
				MOVEI	T1,ANYAC;$
	      GLOAD;
	  ELSE;..MAYBE LOP WAS PUSHED;
	    IF LOP IS IN THE STACK
				T.STK	(LOP);
	    THEN;..PTR WAS PUSHED DUE TO ACC CONFLICT. OK UNLESS 2 WORD OPD;
	      BEGIN
		IF LOP<TYPE> = LONG REAL OR STRING
				T.TWO	(LOP);
		THEN;..WE MUST RETRIEVE THE POINTER FROM THE STACK;
		  BEGIN
;[220] DON'T ASSUME ANY FREE REGISTER, ALLOCATE ONE USING GLOAD
		    PUSH	SP,LOP		;[220] SAVE LOP
	    ;LEX(LOP) _ (SAME,INTEGER,SAME,STACKED) ;[220]
		    TLZ		LOP,$TYPE!$AM	;[220]
		    TLO		LOP,$I!$SP	;[220]
;[220] LOAD LOP INTO NEXT FREE AC
		    MOVE	T,LAC		;[276] GET LAST AC USED BY GLOAD
		    SUBI	T,(SYM)		;[276] CALCULATE AC DISTANCE
		    JUMPLE	T,EDT276	;[276] DISTANCE IS NEG., OK
		    CAILE	T,2		;[276] IS AC > 2 AWAY FROM SYM?
		    JRST	EDT276		;[276] YES, OK - USE AS IS
		    MOVE	T1,LAC		;[276] NO, GET LAC AGAIN
		    SUB		T1,T		;[276] USE NEXT FREE AC
		    CAIG	T1,1		;[276] IS AC NUMBER OK?
		    MOVEI	T1,14		;[276] NO, TOO LOW - WRAP AROUND
		    MOVEM	T1,LAC		;[276] YES, STORE NEW LAC VALUE
EDT276:		    MOVE	T,OPMVLP	;[276][220] AND FOOL GLOAD
		    MOVEI	T1,ANYAC	;[276][262]
		    GLOAD			;[220]
;[220] LEX(LOP) _ (OLD,OLD,OLD,POINTER)
		    TLZ		LOP,$TYPE!$AM	;[220]
		    POP		SP,T4		;[220]
		    HLRZ	T4,T4		;[220]
		    ANDI	T4,$TYPE	;[220]
		    TLO		LOP,$PTR(T4)	;[220]
		  ENDD
		;..ELSE LOP IS NOT A 2 WORD OPERAND;
		FI
	      ENDD
	    ;..ELSE LOP WAS NOT STACKED;
	    FI
	  FI
	ENDD
      FI
      ;..ALL IS READY AND WE CAN PERFORM THE ASSIGNMENT;
      IF LOP IS A BYTE POINTER
				SKIPN	0,CGATMP;$
				GOTO	FALSE;$
      THEN;..GENERATE CODE FOR BYTE ASSIGNMENT;
	BEGIN
	  ;PLUNK(DPB,SYM,LOP);
				MOVE	T,OPBYT3;$
				F.LOCN	(T1,SYM);
				HRR	T,LOP;$
				PLUNK;
	  ;LEX(SYM) _ (EXPR,INTEGER,SIMPLE,ACC);
				TLZ	SYM,$KIND!$TYPE!$STATUS!$AM;$
				TLO	SYM,$EXP!$I!$SIM!$ACC;$
	ENDD
      ELSE;..DO A NORMAL MOVE TO MEMORY;
	IF SYM<TYPE> = STRING
				T.S	(SYM);$
	THEN;..PLANT CALL TO STRASS
	    BEGIN
				MOVE	T,OPLPSH;$
	 			MOVEI	T1,SP;$
	    ; PUSH SYM
	    PLUNK(SYM);$
EDIT(032) ; ALLOW FOR THE CASE OF LOP IN AC 0 OR 1 
		IF LOP IN AC 0 OR 1 ; [E032]
				HRLEI	T,-1(LOP)	; [E032]
				TLNN	LOP,$AMAC	; [E032]
				JUMPLE	T,TRUE		; [E032]
				GOTO	FALSE		; [E032]
		THEN ; [E032]
; WE HAVE NOW PUSHED SYM FROM SOME ACCS ONTO THE STACK. WE WILL NOT
;USE THESE ACCS ANY MORE, AS WE ARE ABOUT TO ELABORATE THE RESULT OF
;STRASS (WHICH WILL BE IN AC 0 & 1) INTO SYM. THEREFORE WE CAN USE ONE
;OF THE ACCS THAT SYM WAS IN WITHOUT ANY FEAR OF LATER ACC CONFLICT !!.
				MOVSI	T,(<MOVE>)	; [E032]
				HRRI	T,(LOP)		; [E032]
				HRRI	LOP,1(SYM)	; [E032]
				F.LOCN(T1,LOP)		; [E032]
		PLUNK; [E032]
		FI ; [E032]
	    ; PUSH LOP
				MOVE	T,OPLPSH;$
				MOVEI	T1,SP;$
	    PLUNK(LOP);$
				MOVE	T,OPSTRA;$
	    PLUNKI;
	    ;..SYM<LEX> _ (EXPR,SIM,AC0)
				TLZ	SYM,$KIND!$STATUS!$AM;$
				TLO	SYM,$EXP!$SIM!$ACC;$
				TRZ	SYM,777777;$
EDIT(200); REMEMBER THAT CALL TO STRASS WILL USE AC0 AND AC1
	    ;HANDLE := HANDLE OR <AC0,AC1>	;[200]
				MOVSI	T,3	;[200] MARK REGISTERS 0 AND 1 AS USED
	    			IORM	T,HANDLE	;[200] IN HANDLE
	    ENDD;
	FI;
        ;PLUNK(ASSIGN,LOP,SYM);
				F.TRANK	(T,SYM);
				MOVE	T,OPASS(T);$
				F.LOCN	(T1,SYM);
				PLUNK	(LOP);
      FI
    ENDD;
  FI
  LCGAS4:
  CLOSE(SYM);
  ;..COMBINE LEXEXES AND COMPOSITE NAMES;
    COMBASSIGN;
 ENDD
 FI
LCGAS1:
ENDD	; CGASS
	SUBTTL	CODE GENERATION ROUTINES	* CGBIN *

PROCEDURE CGBIN

	;..GENERATE CODE TO PERFORM A BINARY OPERATION;
	    ;  ON ENTRY, OPERATION LEXEME IS IN OP;
	    ;  OPERAND LEXEMES ARE IN LOP AND SYM;
	;  IF BOTH OPERANDS ARE CONSTANTS, THE OPERATION IS USUALLY
	    ;  DONE AT COMPILE TIME, A NEW CONSTANT IS GENERATED,
	    ;  AND NO CODE IS PRODUCED.
	;  OPERANDS WILL BE REVERSED IF POSSIBLE, AND OPERATIONS
	    ;  MAY ALSO BE REVERSED (E.G., "<" BECOMES ">").
	;  ARITHMETIC TYPES WILL BE MATCHED BY CONVERTING ONE
	    ;  OPERAND TO THE TYPE OF THE OTHER
	    ;  (IN THE ORDERING INTEGER => REAL => LONG REAL).
	;  SPECIAL CASES FOR BINARY OPERATIONS:
	    ;  LOP ^ 2		(GENERATES "MULTIPLY  LOP,LOP")
	    ;  LOP DIV (2^N)	(GENERATES "ASH  -N")
	    ;  LOP * (2^N)	(GENERATES "ASH   N")
	    ;  LOP + (-CONST)	(CHANGED TO (LOP - CONST))
	;  RESULT IS A CLOSED PORTION WHOSE LEXEME IS IN SYM;

BEGIN
 LOCAL LACSAV;
 IF LOP IS AN ERROR LEXEME
				JUMPGE	LOP,FALSE;$
 THEN;..SET RESULT LEXEME AND LEAVE;
   ERRLEX;
 ELSE;..NO ERRORS YET ..... GO ON;
 BEGIN
  ;..SET REV OFF;
				MOVNI	REV,SYM;$
  IF OP IS ARITHMETIC
				F.DISC	(T);
				CAILE	T,OPMINUS-OPCODE;$
				GOTO	FALSE;$
  THEN;..ARITHMETIC OPERATION;
    BEGIN
      IF LOP<TYPE> = ARITH AND SYM<TYPE> = ARITH
				TLNN	LOP,$ARC;$
				T.ARITH	(SYM);
      THEN;..OPERANDS ARE ARITHMETIC;
        BEGIN
	  IF OP = "REM" OR "DIV"
				MOVE	T,OP;$
				CAMN	T,ZREM;$
				GOTO	TRUE;$
				CAME	T,ZDIV;$
				GOTO	FALSE;$
	  THEN;..MUST DO AN INTEGER DIVIDE;
	    BEGIN
	      IF LOP<TYPE> = INTEGER AND SYM<TYPE> = INTEGER
				TLNN	LOP,$TYPE-$I;$
				T.I	(SYM);
	      THEN;..OPERANDS ARE INTEGERS;
		BEGIN
		  IF NOT TREATCONST
				TREATCONST;
				JUMPN	T,FALSE;$
		  THEN;..OPERANDS ARE NOT BOTH CONSTANTS;
		    BEGIN
		      ;..GIVE LOP SPECIAL TYPE SO LOAD WILL USE 2 AC'S;
				TLZ	LOP,$TYPE;$
				TLO	LOP,$IDI;$
		      IF VALUE OF LOP IN LAST AC <AC13> OR NOT IN AC
				TLNE	LOP,$AM-$ACC;$
				GOTO	TRUE;$
				F.LOCN	(T,LOP);
				CAIE	T,A13;$
				GOTO	FALSE;$
		      THEN;..MUST MOVE LOP TO AN AC PAIR;
			BEGIN
			  LOAD(LOP,ANYAC);
			ENDD
		      FI
		      SETUP;
		      ;..RESET TYPE TO INTEGER;
				TLZ	LOP,$TYPE;$
				TLO	LOP,$I;$
		        ;EMITCODE(IDIV,LOP,SYM,2);
				MOVE	T,OPDIV;$
				F.LOCN	(T1,LOP);
				HRLI	T1,2;$
				EMITCODE(SYM);
		      ;LEX(SYM) _ (EXPR,INTEGER,SIMPLE,LOP);
				TLZ	SYM,$KIND!$TYPE!$STATUS!$AM;$
				TLO	SYM,$EXP!$I!$SIM!$ACC;$
				HRR	SYM,LOP;$
		      IF OP = "REM"
				T.OPER	(ZREM);
		      THEN;..RESULT WILL BE IN AC+1;
			;SYM<LOCN> _ SYM<LOCN> + 1;
				HRRZ	T,SYM;$
				ADDI	T,1;$
				HRR	SYM,T;$
		      FI
		      CLOSE(SYM);
		      COMBLEX;
		    ENDD
		  FI
		ENDD
	      ELSE;..OPERANDS ARE NOT INTEGERS;
		FAIL(67,FRIED,SYM,NON-INTEGER OPERAND FOR "REM" OR "DIV");
	      FI
	    ENDD
	  ELSE;..OP NEQ "REM" AND OP NEQ "DIV";
	    IF OP = "^"
				T.OPER	(ZPOW);
	    THEN;..POWER OPERATION;
	      BEGIN
		IF NOT TREATCONST
				TREATCONST;
				JUMPN	T,FALSE;$
		THEN;..OPERANDS ARE NOT BOTH CONSTANTS;
		  BEGIN
		    IF SYM = IMMEDIATE AND SYM<VALUE> = 2
				F.LOCN	(T,SYM);
				CAIN	T,2;$
				T.IMM	(SYM);
		    THEN;..WE CAN USE MULTIPLY INSTEAD OF POWER;
			;..( LOP ^ 2 = LOP * LOP );
		      BEGIN
			IF LOP IS A POINTER
				T.PTR	(LOP);
			THEN;..LOAD VALUE INTO SAME ACC USED BY PTR;
				F.LOCN	(T2,LOP);
			  LOAD(LOP,@T2);
			ELSE;..NOT A POINTER;
			  IF LOP IS SINGLE
				T.SINGLE(LOP);
			  THEN;..MAKE A PORTION TO LOAD LOP INTO AN ACC;
			    LOAD(LOP,ANYAC);
			  FI
			FI
			REOPEN(LOP);
			;..GENERATE (MULTIPLY,LOP,LOP);
			;SYM _ LOP;
				MOVE	SYM,LOP;$
			;OP _ "*";
				MOVE	T,ZTIMES;$
				MOVEM	T,OP;$
			;GO AND EMIT THE "*" OPERATION;
				GOTO	LCGBI3;$
		      ENDD
		    FI
		    ;..COMBINE PORTIONS;
		      MARRY;
		    IF REV
				T.REV;
		    THEN;..PORTIONS WERE REVERSED;
		      BEGIN
			;..EXCHANGE THE LEXEMES AGAIN;
				EXCH	LOP,SYM;$
			;..SET REV OFF;
				MOVNI	REV,SYM;$
		      ENDD
		    FI
		    ;..WE MUST NOW STACK BOTH OPERANDS FOR THE POWER SR;
		    EDIT(044);Don't force all constants to D.P.
		    IF SYM<TYPE> = LONG REAL		; [E044]
				T.LR	(SYM)		; [E044]
		    THEN;				; [E044]
		      BEGIN;				; [E044]
			IF SYM = PSEUDO-LONG CONSTANT	; [E044]
				T.CONST	(SYM)		; [E044]
				TLNE	SYM,$CT-$IMM	; [E044]
				TLNN	SYM,$DEC	; [E044]
				GOTO	FALSE		; [E044]
				F.LOCN	(T2,SYM)	; [E044]
				ADD	T2,CONTAB	; [E044]
				SKIPL	A1,3(T2)	; [E044]
				GOTO	FALSE		; [E044]
			THEN;				; [E044]
			  BEGIN;			; [E044]
			    IF LOP # GENUINE LONG REAL	; [E044]
				TLNE	LOP,$TYPE-$LR	; [E044]
				GOTO	TRUE		; [E044]
				T.CONST	(LOP)		; [E044]
				TLNE	LOP,$CT-$IMM	; [E044]
				TLNN	LOP,$DEC	; [E044]
				GOTO	FALSE		; [E044]
				F.LOCN	(T1,LOP)	; [E044]
				ADD	T1,CONTAB	; [E044]
				SKIPL	3(T1)		; [E044]
				GOTO	FALSE		; [E044]
			    THEN;SYM SHOULD BE REAL	; [E044]
				MOVE	T3,A0		; [E044]
				MOVE	A0,2(T2)	; [E044]
				TLZ	A1,(1B0)	; [E044]
				PUSHJ	SP,CTLRR	; [E044]
				EXCH	T3,A0		; [E044]
				TOCT	(1,SYM)		; [E044]
				TLZ	SYM,$TYPE	; [E044]
				TLO	SYM,$R		; [E044]
				GOTO	LCPOW1		; [E044]
			    ELSE;SYM SHOULD BE LONG	; [E044]
				MOVE	T3,2(T2)	; [E044]
				MOVE	T4,3(T2)	; [E044]
				TLZ	T4,(1B0)	; [E044]
				TOCT	(2,SYM)		; [E044]
			    FI;				; [E044]
			  ENDD;				; [E044]
			ELSE; SYM IS GENUINE LONG REAL	; [E044]
			  IF LOP = PSEUDO-LONG REAL	; [E044]
				TLNN	LOP,$TYPE-$LR	; [E044]
				T.CONST	(LOP)		; [E044]
				TLNE	LOP,$CT-$IMM	; [E044]
				TLNN	LOP,$DEC	; [E044]
				GOTO	FALSE		; [E044]
				F.LOCN	(T2,LOP)	; [E044]
				ADD	T2,CONTAB	; [E044]
				SKIPL	T4,3(T2)	; [E044]
				GOTO	FALSE		; [E044]
			  THEN;MAKE LOP GENUINE LONG	; [E044]
				MOVE	T3,2(T2)	; [E044]
				TLZ	T4,(1B0)	; [E044]
				TOCT	(2,LOP)		; [E044]
			  FI;				; [E044]
			FI;				; [E044]
		      ENDD;				; [E044]
		    ELSE;SYM IS NOT LONG REAL		; [E044]
		    LCPOW1:				; [E044]
		      IF LOP = PSEUDO-LONG REAL		; [E044]
				TLNN	LOP,$TYPE-$LR	; [E044]
				T.CONST	(LOP)		; [E044]
				TLNE	LOP,$CT-$IMM	; [E044]
				TLNN	LOP,$DEC	; [E044]
				GOTO	FALSE		; [E044]
				F.LOCN	(T2,LOP)	; [E044]
				ADD	T2,CONTAB	; [E044]
				SKIPL	A1,3(T2)	; [E044]
				GOTO	FALSE		; [E044]
		      THEN;CONVERT LOP TO REAL		; [E044]
				MOVE	T3,A0		; [E044]
				MOVE	A0,2(T2)	; [E044]
				TLZ	A1,(1B0)	; [E044]
				PUSHJ	SP,CTLRR	; [E044]
				EXCH	T3,A0		; [E044]
				TOCT	(1,LOP)		; [E044]
				TLZ	LOP,$TYPE	; [E044]
				TLO	LOP,$R		; [E044]
		      FI;				; [E044]
		    FI;					; [E044]
EDIT(110); Check for variables already on the stack
		    IF SYM IS IN THE STACK		; [E110]
				T.STK	(SYM)		; [E110]
		      THEN; PUT IT BACK IN AN ACC	; [E110]
				MOVE	T,OPMVSM	; [E110]
				MOVEI	T1,ANYAC	; [E110]
			GLOAD;				; [E110]
		      FI;				; [E110]
		    IF LOP<TYPE> = LONG REAL
				T.LR	(LOP);
		    THEN
		      ;OPN IS LPUSH;
				MOVE	T,OPLPSH;$
		    ELSE;..SHORT OPERAND;
		      BEGIN
			IF LOP IS IMMEDIATE
				T.IMM	(LOP);
			THEN;..PUT CONSTANT IN TABLE SO IT CAN BE PUSHED;
			  BEGIN
			    IF LOP<TYPE> = INTEGER
				T.I	(LOP);
			    THEN;..IMMED. CONST. GOES TO RIGHT HALF OF T3;
				HRRZ	T3,LOP;$
			    ELSE;..IMMED. CONST. GOES TO LEFT HALF OF T3;
				HRLZ	T3,LOP;$
			    FI
			    ;..PUT CONSTANT INTO TABLE;
			      TOCT(1,LOP);
			  ENDD
			FI
			;..OPN IS "PUSH";
				MOVE	T,OPPUSH;$
		      ENDD
		    FI
		    ;..PUSH LOP;
		    ;PLUNK(OPN,SP,LOP);
				MOVEI	T1,SP;$
				PLUNK	(LOP);
		    IF SYM<TYPE> = LONG REAL
				T.LR	(SYM);
		    THEN
		      ;OPN IS LPUSH;
				MOVE	T,OPLPSH;$
		    ELSE;..SHORT OPERAND;
		      BEGIN
			IF SYM IS IMMEDIATE
				T.IMM	(SYM);
			THEN;..PUT CONSTANT IN TABLE SO IT CAN BE PUSHED;
			  BEGIN
			    IF SYM<TYPE> = INTEGER
				T.I	(SYM);
			    THEN;..IMMED. CONST. GOES TO RIGHT HALF OF T3;
				HRRZ	T3,SYM;$
			    ELSE;..REAL IMM. CONST. GOES TO LEFT OF T3;
				HRLZ	T3,SYM;$
			    FI
			    ;..PUT CONSTANT INTO TABLE;
			      TOCT(1,SYM);
			  ENDD
			FI
			;..OPN IS "PUSH";
				MOVE	T,OPPUSH;$
		      ENDD
		    FI
		    ;..PUSH SYM;
		    ;PLUNK(OPN,SP,SYM);
				MOVEI	T1,SP;$
				PLUNK	(SYM);
		    ;..GET POWER INFORMATION WORD;
				F.TRANK	(T3,LOP);
				LSH	T3,2;$
				F.TRANK	(T,SYM);
				OR	T3,T;$
				MOVE	T3,OPPOW(T3);$
		    IF SYM<TYPE> NEQ INTEGER
				TN.I	(SYM);
		    THEN;..PUT CODE VALUE IN AC1;
		      BEGIN
		        ;PLUNK(MOVEI,AC1,POWER CODE);
				MOVE	T,T3;$
				ANDI	T,3;$
				HLL	T,OPMVI1;$
				PLUNKI;
			;..BOOK AC1 USED;
				MOVSI	T,2;$
				IORM	T,HANDLE;$
		      ENDD
		    ELSE;..EXPONENT IS AN INTEGER;
		      BEGIN
			IF LOP<TYPE> = INTEGER
				T.I	(LOP);
			THEN;..INTEGER ^ INTEGER. RESULT MAY BE INT. OR REAL;
			  BEGIN
			    IF SYM = CONSTANT GEQ ZERO
				T.CONST	(SYM);
				F.LOCN	(T,SYM);
				ADD	T,CONTAB;$
				SKIPGE	0,1(T);$
				GOTO	FALSE;$
			    THEN;..CODE _ 0 AND RESULT WILL BE INTEGER;
			      BEGIN
				;POWER CODE _ 0;
				MOVEI	T,0;$
				;RESULT.TYPE _ INTEGER;
				TRZ	T3,$TYPE;$
				TRO	T3,$I;$
			      ENDD
			    ELSE;..CODE _ 1 AND RESULT WILL BE REAL;
			      ;POWER CODE _ 1;
				MOVEI	T,1;$
			    FI
			    ;..PUT CODE VALUE IN AC1;
			    ;PLUNK(MOVEI,AC1,POWER CODE);
				HLL	T,OPMVI1;$
				PLUNKI;
			    ;..BOOK AC0-AC5 USED;
				MOVSI	T,77;$
				IORM	T,HANDLE;$
			  ENDD
			FI
		      ENDD
		    FI
		    ;..CALL POWER SUBROUTINE;
		    ;PLUNK(POWER NAME);
				HLLZ	T,T3;$
				PLUNKI;
		    IF RESULT.TYPE = LONG REAL
				ANDI	T3,$TYPE;$
				CAIE	T3,$LR;$
				GOTO	FALSE;$
		    THEN;..BOOK AC0-AC13 USED;
				MOVSI	T,7777;$
		    ELSE;..BOOK AC0-4 USED;
				MOVSI	T,37;$
		    FI
				IORM	T,HANDLE;$
		    ;LEX(SYM) _ (EXPR,RESULT.TYPE,SIMPLE,AC0);
				TLZ	SYM,$KIND!$TYPE!$STATUS!$AM;$
				TLO	SYM,$EXP!$SIM!$ACC;$
				TSO	SYM,T3;$
				HRRI	SYM,0;$
		    CLOSE(SYM);
		    COMBLEX;
		  ENDD
		;..ELSE BOTH OPDS WERE CONSTS AND A NEW CONST WAS GENERATED;
		FI
	      ENDD
	    ELSE;..OP NEQ "^" OR "REM" OR "DIV";
	      BEGIN
		IF OP = SLASH AND LOP = INTEGER AND SYM = INTEGER
				T.OPER	(ZSLASH);
				TLNN	LOP,$TYPE-$I;$
				T.I	(SYM);
		THEN;..SLASH OPERATION REQUIRES REAL OPERANDS;
		  ;CONVERT(REAL,SYM);
				MOVEI	T,$R;$
		    CONVERT;
		FI
		IF NOT CHECKARITH
				CHECKARITH;
				JUMPN	T,FALSE;$
		THEN;..OPERANDS NOW HAVE MATCHING ARITHMETIC TYPES;
		  BEGIN
		    IF NOT TREATCONST
				TREATCONST;
				JUMPN	T,FALSE;$
		    THEN;..OPERANDS ARE NOT BOTH CONSTANTS;
		      BEGIN
			SETUP;
			IF OP = "*" AND SYM = IMMED. INT. = 2^N (0 LEQ N LSS 18)
				MOVE	T,OP;$
				CAMN	T,ZTIMES;$
				TLNE	SYM,$AM-$IMM+$TYPE-$I;$
				GOTO	FALSE;$
				HRLZ	T,SYM;$
				JFFO	T,.+2;$
				GOTO	FALSE;$
				LSH	T,1(T1);$
				JUMPN	T,FALSE;$
			THEN;..WE CAN SHIFT RATHER THAN MULTIPLY;
			  BEGIN
			    ;PLUNK(ASH,LOP,N);
				MOVE	T,OPASHL;$
				SUB	T,T1;$
				F.LOCN	(T1,LOP);
				PLUNK;
			    ;GO AND SET UP THE LEXEME;
				GOTO	LCGBI4;$
			  ENDD
			FI
			IF OP = "+" AND SYM = NEGATED IMM. INT. CONSTANT
				T.OPER	(ZPLUS);
				TLNN	SYM,$CONST+$TYPE-$I;$
				TLNN	SYM,$CT-$IMM;$
				GOTO	FALSE;$
				F.LOCN	(T,SYM);
				ADD	T,CONTAB;$
				MOVN	T1,1(T);$
				JUMPL	T1,FALSE;$
				CAILE	T1,-1;$
				GOTO	FALSE;$
			THEN;..CHANGE "A + (- CONSTANT)" TO "A - CONSTANT";
			  BEGIN
			    ;OP _ "-";
				MOVE	T,ZMINUS;$
				MOVEM	T,OP;$
			    ;LEX(SYM) _ (IMMED.,SAME,SAME,-(VALUE(SYM)));
				TLZ	SYM,$AM;$
				TLO	SYM,$IMM;$
				HRR	SYM,T1;$
			  ENDD
			FI
			LCGBI3:
		        ;..GENERATE THE INSTRUCTION TO PERFORM "OP";
			;EMITCODE(OPN,LOP,SYM,LENGTH);
				F.TRANK	(T,SYM);
				F.DISC	(T1);
				ADD	T,T1;$
				MOVE	T,OPCODE(T);$
				F.LOCN	(T1,LOP);
			IF LOP IS LONG REAL
				T.LR	(LOP);
			THEN
			  BEGIN
				HLRZ	T1,T
				LSH	T1,-11
				TRZ	T1,700
				CAIGE	T1,22
				MOVE	T,KIOPS(T1)
			; LENGTH _ 2;
				HRLI	T1,2
			  ENDD
			ELSE
			; LENGTH _ 1 (TYPE # LONG REAL)
				HRLI	T1,1;$
			FI
EDIT(026); DONT DESTROY LENGTH CODE CAREFULLY SET UP IN L.H. OF T1
				HRR	T1,LOP	; [E026]
				EMITCODE(SYM);
			LCGBI4:
			;LEX(SYM) _ (EXPR,SAME,SIMPLE,LOP);
				TLZ	SYM,$KIND!$STATUS!$AM;$
				TLO	SYM,$EXP!$SIM!$ACC;$
				HRR	SYM,LOP;$
			CLOSE(SYM);
			COMBLEX;
		      ENDD
		    ;..ELSE BOTH OPDS WERE CONSTS AND A NEW CONST WAS GENERATED;
		    FI
		  ENDD
		ELSE;..TYPE OF AN OPERAND IS NOT INTEGER, REAL, OR LONG REAL;
		  FAIL(68,FRIED,SYM,COMPLEX OPERAND FOR ARITH OPERATOR);
		FI
	      ENDD
	    FI
	  FI
	ENDD
      ELSE;..AN OPERAND IS NOT ARITHMETIC;
	FAIL(69,FRIED,SYM,NON-ARITH OPERAND FOR ARITH OPERATOR);
      FI
    ENDD
  ELSE;..OP IS NOT ARITHMETIC;
    IF OP = RELATIONAL
				T.RELATION(T);
    THEN;..WE HAVE A RELATION;
      BEGIN
	IF NOT CHECKARITH
				CHECKARITH;
				JUMPN	T,FALSE;$
        THEN;..OPERANDS NOW HAVE MATCHING ARITHMETIC TYPES;
	  BEGIN
	    IF NOT TREATCONST
				TREATCONST;
				JUMPN	T,FALSE;$
	    THEN;..OPERANDS ARE NOT BOTH CONSTANTS;
	      BEGIN
	        SETUP;
		IF SYM<TYPE> = LONG REAL
				T.LR	(SYM);
		THEN;..OPERANDS ARE BOTH LONG REAL;
		  BEGIN
		    ;..SUBTRACT SYM FROM LOP;
		    ;EMITCODE(LFSB,LOP,SYM,3);
				MOVE	T,OPLFSB;$
				F.LOCN	(T1,LOP);
				HRLI	T1,3;$
				EMITCODE(SYM);
		    ;..TEST RESULT VS. ZERO;
		    ;PLUNK(OPN+1,LOP,ZERO);
				F.DISC	(T);
				MOVE	T,OPCODE+1(T);$
				F.LOCN	(T1,LOP);
				PLUNK;
		  ENDD
	        ELSE;..OPERANDS ARE INTEGER OR REAL;
		  ;..COMPARE THE OPERANDS;
		  IF SYM<AM> = IMMEDIATE
				T.IMM	(SYM);
		  THEN;..IMMEDIATE CONSTANT;
		    BEGIN
		      IF SYM<TYPE> = REAL
				T.R	(SYM);
		      THEN;..REAL IMMEDIATE CONSTANT;
			BEGIN
			  ;..SUBTRACT SYM FROM LOP;
			  ;EMITCODE(FSBR,LOP,SYM,1);
				MOVE	T,OPFSBR;$
				F.LOCN	(T1,LOP);
				HRLI	T1,1;$
				EMITCODE(SYM);
			  ;..TEST RESULT VS. ZERO;
			  ;PLUNK(OPN+1,LOP,0);
				F.DISC	(T);
				MOVE	T,OPCODE+1(T);$
				F.LOCN	(T1,LOP);
				PLUNK;
			ENDD
		      ELSE;..INTEGER IMMEDIATE CONSTANT;
			;EMITCODE(OPN+1,LOP,SYM,1);
				F.DISC	(T);
				MOVE	T,OPCODE+1(T);$
				F.LOCN	(T1,LOP);
				HRLI	T1,1;$
				EMITCODE(SYM);
		      FI
		    ENDD
		  ELSE;..NON-IMMEDIATE OPERAND;
		    ;EMITCODE(OPN,LOP,SYM,1);
				F.DISC	(T);
				MOVE	T,OPCODE(T);$
				F.LOCN	(T1,LOP);
				HRLI	T1,1;$
				EMITCODE(SYM);
		  FI
		FI
		LCGBI2:
		;..RESULT MUST BE "TRUE" OR "FALSE". GENERATE IT;
		;PLUNK(TDZA,LOP,LOP);
				MOVE	T,OPTDZA;$
				F.LOCN	(T1,LOP);
				PLUNK	(LOP);
		;PLUNK(SETO,LOP,0);
				MOVE	T,OPSETO;$
				F.LOCN	(T1,LOP);
				PLUNK;
		;LEX(SYM) _ (EXPR,BOOLEAN,SIMPLE,LOP);
				TLZ	SYM,$KIND!$TYPE!$STATUS!$AM;$
				TLO	SYM,$EXP!$B!$SIM!$ACC;$
				HRR	SYM,LOP;$
		CLOSE(SYM);
		COMBLEX;
	      ENDD
	    ;..ELSE BOTH OPDS WERE CONSTS AND A NEW CONST WAS GENERATED;
	    FI
	  ENDD
	ELSE;..A RELATIONAL OPERAND IS NOT INTEGER OR REAL OR LONG REAL;
	  IF LOP<TYPE> = STRING AND SYM<TYPE> = STRING
				TLNN	LOP,$TYPE-$S;$
				T.S	(SYM);
	  THEN;..RELATION BETWEEN STRINGS;
	    BEGIN
	      ;..PUT OPERANDS IN A0-1 AND A2-3 FOR THE COMPARE SR;
	      IF VALUE OF LOP IS NOT IN AC0
				TN.AC0	(LOP);
	      THEN;..MUST PUT IT INTO AC0 AND AC1;
		LOAD(LOP,A0);
	      FI
	      IF VALUE OF SYM IS NOT IN AC2
				TLNE	SYM,$AM-$ACC;$
				GOTO	TRUE;$
				F.LOCN	(T,SYM);
				CAIN	T,A2;$
				GOTO	FALSE;$
	      THEN;..MUST PUT IT INTO AC2 AND AC3;
		;..FUDGE LAC=A4 TO MAKE LOAD WORK;
				MOVEI	T,A4;$
				EXCH	T,LAC;$
				MOVEM	T,LACSAV;$
		LOAD(SYM,A2);
		;..RESTORE LAC;
				MOVE	T,LACSAV;$
				MOVEM	T,LAC;$
	      FI
	      MERGEPORTIONS;
	      IF LOP NOT IN AC0
				TN.AC0	(LOP);
	      THEN;..IT WAS MOVED DUE TO ACC CONFLICT. PUT IT BACK IN AC0;
				MOVE	T,OPMVLP;$
				MOVEI	T1,A0;$
		GLOAD;
	      FI
	      ;..GENERATE CALL ON COMPARE SUBROUTINE;
				MOVE	T,OPCMPR;$
				PLUNKI;
	      ;..RESULT IS -1, 0, OR +1 IN REGISTER AC0;
				HRRI	LOP,A0;$
	      ;..GENERATE THE INST. TO TEST RESULT OF COMPAR VS. ZERO;
	      ;EMITCODE(OPN+1,AC0,0,1);
				F.DISC	(T);
				MOVE	T,OPCODE+1(T);$
				HRLZI	T1,1;$
				EMITCODE;
	      ;..NOW GO GENERATE THE BOOLEAN RESULT;
				GOTO	LCGBI2;$
	    ENDD
	  ELSE;..TYPES CANNOT BE CORRECT;
	    FAIL(70,HARD,NSYM,NON-ARITH OPERAND FOR RELATIONAL OPERATOR);
	  FI
        FI
      ENDD
    ELSE;..OP IS NOT ARITHMETIC OR RELATIONAL. IT MUST BE BOOLEAN;
      BEGIN
        IF LOP<TYPE> = BOOLEAN AND SYM<TYPE> = BOOLEAN
				TLNN	LOP,$TYPE-$B;$
				T.B	(SYM);
        THEN;..OPERANDS ARE BOTH BOOLEAN;
	  BEGIN
	    IF NOT TREATCONST
				TREATCONST;
				JUMPN	T,FALSE;$
	    THEN;..OPERANDS ARE NOT BOTH CONSTANTS;
	      BEGIN
	        SETUP;
	        ;..GENERATE THE INSTRUCTION TO PERFORM "OP";
	        ;EMITCODE(OPN,LOP,SYM,1);
				F.DISC	(T);
				MOVE	T,OPCODE(T);$
				F.LOCN	(T1,LOP);
				HRLI	T1,1;$
				EMITCODE(SYM);
		;LEX(SYM) _ (EXPR,SAME,SIMPLE,LOP);
				TLZ	SYM,$KIND!$STATUS!$AM;$
				TLO	SYM,$EXP!$SIM!$ACC;$
				HRR	SYM,LOP;$
		CLOSE(SYM);
		COMBLEX;
	      ENDD
	    ;..ELSE BOTH OPDS WERE CONSTS AND A NEW CONST WAS GENERATED;
	    FI
	  ENDD
	ELSE;..AN OPERAND IS NOT BOOLEAN;
	  FAIL(71,FRIED,SYM,NON-BOOLEAN OPERAND FOR BOOLEAN OPERATOR);
	FI
      ENDD
    FI
  FI
 ENDD
 FI
ENDD	; CGBIN
	SUBTTL	CODE GENERATION ROUTINES	* CGUNA *

PROCEDURE CGUNA

	;..PROCESS UNARY OPERATORS;
	    ;  GENERATE CODE TO PERFORM UNARY "+", "-", AND "NOT".
	;  ON ENTRY, OPERATION LEXEME IS IN OP;
	    ;  OPERAND IS IN SYM;
	;  RESULT IS A CLOSED PORTION WHOSE LEXEME IS IN SYM;

BEGIN
  ;..SET REV OFF;
				MOVNI	REV,SYM;$
  IF OP = "NOT"
				T.OPER	(ZNOT);
  THEN;..LOGICAL COMPLEMENT;
    BEGIN
      IF SYM<TYPE> NEQ BOOLEAN
				TN.B	(SYM);
      THEN
	FAIL(72,FRIED,SYM,NON-BOOLEAN OPERAND FOR "NOT");
      ELSE;..OPERAND IS BOOLEAN;
        BEGIN
	  IF NOT TRUNACONST
				TRUNACONST;
				JUMPN	T,FALSE;$
          THEN;..OPERAND IS NOT CONSTANT;
            BEGIN
	      IF SYM IS AN EXPR OR A POINTER IN AN ACC
				T.ACC	(SYM);
              THEN;..OPERAND OR ITS POINTER IS ALREADY IN AN AC;
		BEGIN
		  REOPEN(SYM);
		  ;..COMPLEMENT THE OPERAND;
		  ;PLUNK(NOT,SYM,SYM);
				MOVE	T,OPNOT;$
				F.LOCN	(T1,SYM);
				PLUNK	(SYM);
		  ;LEX(SYM) _ (EXPR,SAME,SIMPLE,ACC);
				TLZ	SYM,$KIND!$STATUS!$AM;$
				TLO	SYM,$EXP!$SIM!$ACC;$
		  CLOSE(SYM);
		ENDD
	      ELSE;..OPERAND IS NOT IN AN AC. LOAD ITS COMPLEMENT;
		LOADC(SYM,ANYAC);
	      FI
            ENDD
	  ;..ELSE OPERAND WAS CONSTANT AND A NEW CONST WAS GENERATED;
          FI
        ENDD
      FI
    ENDD
  ELSE;..OP NEQ "NOT".  IT MUST BE "+" OR "-";
    BEGIN
      IF SYM<TYPE> NEQ ARITH
				TN.ARITH(SYM);
      THEN
        FAIL(73,FRIED,SYM,NON-ARITH OPERAND FOR UNARY "+" OR "-");
      ELSE;..OPERAND IS ARITHMETIC;
        BEGIN
          IF OP = UNARY "-"
				T.OPER	(ZUMINUS);
	  THEN;..OP = NEGATE;
	    BEGIN
	      IF NOT TRUNACONST
				TRUNACONST;
				JUMPN	T,FALSE;$
	      THEN;..OPERAND IS NOT CONSTANT;
		BEGIN
		  IF SYM IS A LONG REAL POINTER IN AN ACC
				TLNN	SYM,$AMAC+$TYPE-$LR;$
				TLNN	SYM,$INDC;$
				GOTO	FALSE;$
		  THEN;..VALUE OF OPERAND NOT IN ACC. LOAD ITS NEGATIVE;
				GOTO	LCGUN1;$
		  FI
		  IF SYM IS AN EXPR IN ACC
				T.ACC	(SYM);
		  THEN;..OPERAND OR ITS POINTER IS ALREADY IN AN ACC;
		    BEGIN
		      REOPEN(SYM);
		      ;..NEGATE THE OPERAND;
		      ;PLUNK(MOVN,SYM,SYM) OR PLUNK(DFN,SYM,SYM+1);
				F.TRANK	(T,SYM);
				MOVE	T,OPUMIN(T);
				F.LOCN	(T1,SYM);
				MOVE	T2,SYM;$
				TLZ	T2,777777-$AM;$
				ADD	T,T2;$
				PLUNK;
		      ;LEX(SYM) _ (EXPR,SAME,SIMPLE,ACC);
				TLZ	SYM,$KIND!$STATUS!$AM;$
				TLO	SYM,$EXP!$SIM!$ACC;$
		      CLOSE(SYM);
		    ENDD
		  ELSE;..OPERAND IS NOT IN AN AC. LOAD ITS NEGATIVE;
		    LCGUN1:
		    LOADN(SYM,ANYAC);
		  FI
		ENDD
	      ;..ELSE OPD WAS CONST AND NEGATED CONST WAS GENERATED;
	      FI
	    ENDD
	  ;..ELSE OPERATION IS UNARY "+".  NO ACTION NEEDED;
	  FI
	ENDD
      FI
    ENDD
  FI
ENDD	; CGUNA
	SUBTTL	CODE GENERATION ROUTINES	* TREATCONST *

PROCEDURE TREATCONST

	;..PERFORM BINARY OP AT COMPILE-TIME WHEN BOTH OPDS ARE CONSTANTS.
	    ;  IF AT LEAST ONE OPERAND IS NON-CONSTANT,
	    ;  FLAG (T) IS SET TO "FALSE" (ALL ZEROS);
	    ;  IF BOTH ARE CONSTANT, NEW CONSTANT IS PRODUCED 
	    ;  AND FLAG IS SET TO "TRUE" (ALL ONES).
	;  ON ENTRY, OPERAND LEXEMES ARE IN LOP AND SYM,
	    ;  OPERATION LEXEME IS IN OP.
	;  IF OPERATION = "^", NEW CONSTANT IS PRODUCED ONLY IF
	    ;  EXPONENT IS AN INTEGER.
	;  RESULT LEXEME GOES TO SYM.
	    ;  NEW CONSTANT IS PUT INTO LEXEME IF IT IS IMMEDIATE,
	    ;  OTHERWISE IT IS PUT INTO THE CONSTANT TABLE.

BEGIN
OWN TA0,DPFLAG; TA0 = TEMPORARY TO HOLD A0 (GBREG)	; [E044]
		;DPFLAG SET IF EXPLICIT DOUBLE PRECISION; [E044]
 IF LOP = CONSTANT AND SYM = CONSTANT
				TLNN	LOP,$CONST;$
				T.CONST	(SYM);
 THEN;..WE MUST PRODUCE A NEW CONSTANT;
 BEGIN
  ;..MAKE SURE OVERFLOW FLAGS ARE OFF;
				JFCL	11,LTC2;$
  LTC2:
  IF OP NEQ "^"
				TN.OPER	(ZPOW);
  THEN;..OP IS NOT POWER AND TYPES OF LOP AND SYM MATCH;
  BEGIN
   IF SYM<TYPE> NEQ LONG REAL
				TN.LR	(SYM);
   THEN;..TYPES OF LOP AND SYM ARE NOT LONG REAL;
    BEGIN
      ;T2 _ LOP<LOCN>;
				F.LOCN	(T2,LOP);
      ;..PUT VALUE OF LOP INTO T3;
      IF LOP = IMMEDIATE
				T.IMM	(LOP);
      THEN;..IMMEDIATE LEFT OPERAND;
	IF SYM<TYPE> = REAL
				T.R	(SYM);
	THEN
	  ;FETCH IMMEDIATE REAL CONSTANT;
				HRLZ	T3,T2;$
	ELSE
	  ;FETCH IMMEDIATE INTEGER OR BOOLEAN CONSTANT;
				HRRZ	T3,T2;$
	FI
      ELSE;..LEFT OPERAND IS IN CONSTANT TABLE;
	;FETCH CONSTANT FROM TABLE;
				ADD	T2,CONTAB;$
				MOVE	T3,1(T2);$
      FI
      ;..NOW GENERATE INSTRUCTION  <OPN  T3,SYM>;
      ;..FIRST COMPUTE INCREMENT FOR OPCODE TABLE INDEX;
      IF OP = RELATIONAL
				T.RELATION(T);
      THEN
        ;T1 _ 0;
				SETZ	T1,0;$
      ELSE
	IF SYM<TYPE> = BOOLEAN
				T.B	(SYM);
	THEN
	  ;T1 _ 0;
				SETZ	T1,0;$
        ELSE
	  IF OP="REM"
				T.OPER	(ZREM);
	  THEN; FUDGE INDEX TO GET AN IDIV;
	    ;T1_-2;
				MOVNI	T1,2;$
	  ELSE; USE THE RANK AS AN INDEX;
	    ;T1 _ SYM<RANK>;
				F.TRANK	(T1,SYM);
	  FI
	FI
      FI
      ;T1 _ <OPN T3,0>;
				F.DISC	(T);
				ADD	T,T1;$
				MOVE	T1,OPCODE(T);$
				TLO	T1,T3_5;$
      ;..T2 _ SYM<LOCN>;
				F.LOCN	(T2,SYM);
      IF SYM = IMMEDIATE
				T.IMM	(SYM);
      THEN;..IMMEDIATE RIGHT OPERAND;
	BEGIN
	  IF OP = RELATIONAL
				T.RELATION(T);
	  THEN;..IMMEDIATE RIGHT OPERAND IN A RELATION;
	    BEGIN
	      IF SYM<TYPE> = REAL
				T.R	(SYM);
	      THEN;..REAL IMMEDIATE CONSTANT IN A RELATION;
		BEGIN
		  ;..LOAD CONSTANT INTO T2;
				HRLZ	T2,T2;$
		  ;..ADDRESS OF OPERAND IS T2;
				HRRI	T1,T2;$
		ENDD
	      ELSE;..INTEGER IMMED. CONST. IN A RELATION;
		BEGIN
		  ;..SUBTRACT 10 FROM INST. CODE TO GET IMMED. (I) VARIANT;
		  ;T1<OPCODE> _ T1<OPCODE> - 10;
				TLZ	T1,010000;$
		  ;..LOAD IMMEDIATE CONSTANT;
				HRR	T1,T2;$
		ENDD
	      FI
	    ENDD
	  ELSE;..OP IS NOT A RELATION;
	    BEGIN
	      ;..ADD 1 TO PDP-10 INST. CODE TO GET IMMEDIATE (I) VARIANT;
	      ;T1<OPCODE> _ T1<OPCODE> + 1;
				TLO	T1,001000;$
	      ;..LOAD IMMEDIATE CONSTANT;
				HRR	T1,T2;$
	    ENDD
	  FI
	ENDD
      ELSE;..RIGHT OPERAND IS IN CONSTANT TABLE;
	;LOAD ADDRESS OF CONSTANT;
				ADD	T2,CONTAB;$
				HRRI	T1,1(T2);$
      FI
      ;..INSTRUCTION IS NOW READY;
      IF OP = RELATIONAL
				T.RELATION(T);
      THEN;..WE HAVE A RELATION;
	BEGIN
	  ;..EXECUTE THE INSTRUCTION IN T1;
				XCT	T1;$
	  ;..GENERATE "FALSE" OR "TRUE" CONSTANT;
				TDZA	T3,T3;$
				SETO	T3,0;$
	  ;SYM<TYPE> _ BOOLEAN;
				TLZ	SYM,$TYPE;$
				TLO	SYM,$B;$
        ENDD
      ELSE;..OP IS NOT A RELATION;
	BEGIN
	  ;..EXECUTE THE INSTRUCTION IN T1;
				XCT	T1;$
	  IF OP = "REM"
				T.OPER	(ZREM);
	  THEN;..QUOTIENT IS IN T3, REMAINDER IS IN T4;
	    ;RESULT CONSTANT IS REMAINDER(IDIV);
				MOVE	T3,T4;$
	  FI
	ENDD
      FI
      IF NO OVERFLOW FLAGS SET
				JFCL	11,FALSE;$
      THEN;..NO OVERFLOW.  VALID RESULT WAS PRODUCED;
	STOCON;
      ELSE;..OVERFLOW IN OPERATION ON CONSTANTS. RESULT IS INVALID;
	BEGIN
	  FAIL(74,FRIED,SYM,OVERFLOW WHILE COMBINING CONSTANTS);
	  ERRLEX;
	ENDD
      FI
    ENDD
   ELSE;..OPERANDS ARE LONG REAL;
    BEGIN
     ;..SAVE A0 (GBREG);
				MOVEM	A0,TA0;$
     ;..ASSUME SINGLE PRECISION FOR NOW			; [E044]
				SETOM	DPFLAG		; [E044]
     ;..PUT LEFT VALUE INTO (A0,A1);
     ;.. * * * NOTE THAT A1 IS THE SAME REGISTER AS T;
				F.LOCN	(T4,LOP);
				ADD	T4,CONTAB;$
				MOVE	A0,2(T4);$
				MOVE	A1,3(T4);$
				TLZN	A1,(1B0)	; [E044]
				SETZM	DPFLAG		; [E044]
     ;..PUT RIGHT VALUE INTO (A3,A4);
				F.LOCN	(T4,SYM);
				ADD	T4,CONTAB;$
				MOVE	A3,2(T4);$
				MOVE	A4,3(T4);$
				TLZN	A4,(1B0)	; [E044]
				SETZM	DPFLAG		; [E044]
     IF OP = RELATIONAL
				T.RELATION(T4);
     THEN;..WE HAVE A RELATION. RESULT WILL BE A BOOLEAN CONSTANT;
      BEGIN
	;..SUBTRACT (LONG REAL) SYM FROM LOP;
	;..NOTE THAT A2 (T1) WILL BE CLOBBERED;
        ;EXECUTE <PUSHJ  SP,LFSBC>;
				DFSB	A0,A3;$
	;..COMPARE RESULT WITH ZERO;
	;EXECUTE <OPCODE[OP<DISC>+1]  A0,0>;
				F.DISC	(T4);
				HLLZ	T4,OPCODE+1(T4);$
				XCT	T4;$
	;GENERATE "FALSE" OR "TRUE" CONSTANT IN T3;
				TDZA	T3,T3;$
				SETO	T3,0;$
	;SYM<TYPE> _ BOOLEAN;
				TLZ	SYM,$TYPE;$
				TLO	SYM,$B;$
	;..RESTORE A0;
				MOVE	A0,TA0;$
	;..PUT BOOLEAN CONSTANT AWAY;
	  STOCON;
      ENDD
     ELSE;..NOT A RELATION. RESULT IS A LONG REAL CONSTANT;
      BEGIN
        ;..PERFORM THE OPERATION;
	;.. * * * NOTE THAT A2 (T1) WILL BE CLOBBERED;
	;EXECUTE  <OPCODE[OP<DISC>+3]>;
				F.DISC	(T4);
				XCT	OPCODE+3(T4);$
	;..MOVE RESULT TO (T3,T4);
				MOVE	T3,A0;$
				MOVE	T4,A1;$
	;..RESTORE A0;
				MOVE	A0,TA0;$
	IF NO OVERFLOW IN LONG REAL MULTIPLY OR DIVIDE
				JUMPL	SYM,FALSE;$
EDIT (221); INSERT IN CONSTANT FOLDING ROUTINE IN .CGBIN
				JFOV	FALSE;		;[221]
	THEN;..STORE LONG REAL CONSTANT RESULT;
		;..IF NEITHER OPERAND WAS EXPLICIT DOUBLE PRECISION,
		;..THEN NEITHER IS THE RESULTING CONSTANT.
				SKIPE	DPFLAG		; [E044]
				TLOA	T4,(1B0)	; [E044]
				TLZ	T4,(1B0)	; [E044]
	  TOCT(2,SYM);
	ELSE;..WE HAD AN OVERFLOW IN LONG REAL "*" OR "/";
	  ;..SET UP ERROR LEXEME;
	  FAIL(74,FRIED,SYM,OVERFLOW WHILE COMBINGING CONSTANTS);	;[221]
	  ERRLEX;
	FI
      ENDD
     FI
    ENDD
   FI
  ENDD
  ELSE;..OP IS "^";
  BEGIN
    IF SYM NEQ INTEGER
				TN.I	(SYM);
    THEN;..COMPUTE POWER AT RUN-TIME;
      ;SET T TO "FALSE" AND EXIT;
				GOTO	LTC1;$
    FI
    ;..LOAD BASE (LOP) INTO A0 (AND A1);
    ;T2 _ LOP<LOCN>;
				F.LOCN	(T2,LOP);
    ;..SAVE GBREG (A0);
				MOVEM	A0,TA0;$
    IF LOP<TYPE> = LONG REAL
				T.LR	(LOP);
    THEN;..BASE IS LONG REAL;
      BEGIN;						; [E044]
      ;..PUT LONG CONSTANT INTO REGISTERS A0 AND A1;
				ADD	T2,CONTAB;$
				MOVE	A0,2(T2);$
	IF PSEUDO-LONG REAL CONVERT IT TO A REAL	; [E044]
				SKIPL	A1,3(T2)	; [E044]
				GOTO	FALSE		; [E044]
	THEN;						; [E044]
				TLZ	A1,(1B0)	; [E044]
				PUSHJ	SP,CTLRR	; [E044]
				TLZ	LOP,$TYPE	; [E044]
				TLO	LOP,$R		; [E044]
	FI;						; [E044]
      ENDD;						; [E044]
    ELSE;..BASE IS INTEGER OR REAL;
      BEGIN
   	IF LOP = IMMEDIATE
				T.IMM	(LOP);
	THEN;..IMMEDIATE VALUE MUST BE LOADED INTO A0;
	  BEGIN
	    IF LOP<TYPE> = INTEGER
				T.I	(LOP);
	    THEN
	      ;LOAD IMMEDIATE INTEGER CONSTANT;
				HRRZ	A0,T2;$
	    ELSE
	      ;LOAD IMMEDIATE REAL CONSTANT;
				HRLZ	A0,T2;$
	    FI
  	  ENDD
	ELSE;..LOP HAS A FULLWORD VALUE;
	  ;;..LOAD CONSTANT FROM TABLE;
				ADD	T2,CONTAB;$
				MOVE	A0,1(T2);$
	FI
      ENDD
    FI
    ;..PUT EXPONENT (SYM) INTO A2;
    ;T2 _ SYM<LOCN>;
				F.LOCN	(T2,SYM);
    IF SYM = IMMEDIATE
				T.IMM	(SYM);
    THEN;..IMMEDIATE VALUE MUST BE LOADED INTO A2;
      ;..LOAD IMMEDIATE INTEGER CONSTANT;
				HRRZ	A2,T2;$
    ELSE;..SYM HAS A FULLWORD VALUE;
       ;..LOAD CONSTANT FROM TABLE;
				ADD	T2,CONTAB;$
				MOVE	A2,1(T2);$
    FI
    ;..COPY EXPONENT FOR SIGN CHECK;
				MOVE	T4,A2;$
    ;..EXECUTE THE CALL.  RESULT IN A0 (AND A1);
				F.TRANK	(T2,LOP);
				XCT	OPPOWC(T2);$
    ;..MOVE FIRST WORD OF RESULT TO T3;
				MOVE	T3,A0;$
    ;..RESTORE GBREG (A0);
				MOVE	A0,TA0;$
    IF SYM IS AN ERROR LEXEME
				JUMPGE	SYM,FALSE;$
    THEN;..SET RESULT LEXEME;
      ERRLEX;
    ELSE;..RESULT IS VALID. PUT IT AWAY;
      BEGIN
        IF LOP<TYPE> = LONG REAL
				T.LR	(LOP);
        THEN;..RESULT IS LONG REAL;
          BEGIN
	    ;..MOVE SECOND WORD OF RESULT TO T4;
				MOVE	T4,A1;$
            ;..PUT LONG CONSTANT IN TABLE;
	      TOCT(2,SYM);
            ;LEX(SYM) _ (SAME,LONG REAL,SAME,SAME);
				TLZ	SYM,$TYPE;$
				TLO	SYM,$LR;$
          ENDD
        ELSE;..PUT SHORT CONSTANT AWAY;
          BEGIN
	    IF LOP<TYPE> = INTEGER AND EXPONENT GTE 0
				JUMPL	T4,FALSE;$
				T.I	(LOP);
	    THEN;..TYPE OF SYM SHOULD BE INTEGER (IT ALREADY IS);
	    ELSE;..TYPE OF RESULT SHOULD BE REAL;
	      ;LEX(SYM) _ (SAME,REAL,SAME,SAME);
				TLZ	SYM,$TYPE;$
				TLO	SYM,$R;$
	    FI
	    STOCON;
	  ENDD
	FI
      ENDD
    FI
  ENDD
  FI
  ;..RESULT HAS BEEN COMPUTED. SET FLAG TO TRUE;
  ;T _ "TRUE";
				SETO	T,0;$
 ENDD
 ELSE;..OPERANDS ARE NOT BOTH CONSTANTS AND RESULT CANNOT BE COMPUTED NOW;
   LTC1:
   ;..SET FLAG TO FALSE;
   ;T _ "FALSE";
				SETZ	T,0;$
 FI
ENDD	; TREATCONST
	SUBTTL	CODE GENERATION ROUTINES	* TRUNACONST *

PROCEDURE TRUNACONST;

	;..PERFORM UNARY OP AT COMPILE-TIME IF OPERAND IS A CONSTANT.
	    ;  IF OPERAND IS NOT A CONSTANT, FLAG (T) IS SET TO
	    ;  "FALSE" (ALL ZEROS);
	    ;  IF IT IS A CONSTANT, NEW CONSTANT IS PRODUCED
	    ;  AND FLAG IS SET TO "TRUE" (ALL ONES);
	;  ON ENTRY, OPD LEXEME IS IN SYM AND OPN LEXEME IS IN OP;
	;  RESULT LEXEME GOES TO SYM.
	    ;  NEW CONSTANT IS PUT INTO LEXEME IF IT IS IMMEDIATE,
	    ;  OTHERWISE IT IS PUT INTO THE CONSTANT TABLE;

BEGIN
  IF SYM = CONSTANT
				T.CONST	(SYM);
  THEN;..WE MUST DO SOMETHING;
    BEGIN
      ;T2 _ SYM<LOCN>;
				F.LOCN	(T2,SYM);
      IF SYM<TYPE> = LONG REAL
				T.LR	(SYM);
      THEN;..LONG REAL OPERAND POSSIBLE ONLY FOR UNARY "-";
	BEGIN
	  ;NEGATE LONG CONSTANT INTO T3 AND T4;
				ADD	T2,CONTAB;$
				DMOVN	T3,2(T2)
				TLZ	T4,(1B0)	; [E044]
				SKIPL	3(T2)		; [E044]
				TLZA	T4,(1B0)	; [E044]
				TLO	T4,(1B0)	; [E044]
	  ;..PUT NEW CONSTANT IN TABLE;
	    TOCT(2,SYM);
        ENDD
      ELSE;..SHORT CONSTANT;
        BEGIN
	  IF OP = "NOT"
				T.OPER	(ZNOT);
	  THEN;..COMPLEMENT THE CONSTANT;
	    BEGIN
	      IF SYM = IMMEDIATE
				T.IMM	(SYM);
	      THEN;..PUT COMPLEMENT OF IMMED. CONSTANT INTO T3;
				SETCM	T3,T2;$
	      ELSE;..GET COMPLEMENT OF TABLED CONST. INTO T3;
				ADD	T2,CONTAB;$
				SETCM	T3,1(T2);$
	      FI
	    ENDD
	  ELSE;..OP MUST BE UNARY "-";
	    BEGIN
	      IF SYM = IMMEDIATE
				T.IMM	(SYM);
	      THEN;..CONSTANT IS IN A HALFWORD;
		BEGIN
		  IF SYM<TYPE> = INTEGER
				T.I	(SYM);
		  THEN;..NEGATE IMMED. INTEGER CONST. INTO T3;
				MOVN	T3,T2;$
		  ELSE;..NEGATE IMMED. REAL CONSTANT INTO T3;
				HRLZ	T3,T2;$
				MOVN	T3,T3;$
		  FI
		ENDD
	      ELSE;..CONSTANT TAKES A FULL WORD;
		;NEGATE CONSTANT FROM TABLE INTO T3;
				ADD	T2,CONTAB;$
				MOVN	T3,1(T2);$
	      FI
	    ENDD
	  FI
	  ;..SET UP LEXEME AND STORE IN CONSTANT TABLE;
	  STOCON;
	ENDD
      FI
      ;..UNARY OPERATION IS COMPLETE;
      ;T _ TRUE;
				SETO	T,0;$
    ENDD
  ELSE;..OPERAND IS NOT A CONSTANT. UNARY OP MUST BE GENERATED;
    ;T _ FALSE;
				SETZ	T,0;$
  FI
ENDD	; TRUNACONST
ENDD; OF MODULE MCOD

LIT
END