Trailing-Edge
-
PDP-10 Archives
-
ALGOL-20_29Jan82
-
algol-sources/algfun.mac
There are 8 other files named algfun.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 2
; 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 MFUN;
$PLEVEL=2;
BEGIN
EXPROC CGBIN
EXPROC CLOSE
EXPROC EMITCODE
EXPROC ERRLEX
EXPROC FAIL
EXPROC GLOAD
EXPROC IPLUNK
EXPROC LOAD
EXPROC MERGEPORTIONS
EXPROC PLUNK
EXPROC REOPEN
EXPROC REVORDER
EXPROC TOCT1
EXPROC TOCT2
EXPROC UNSTACK
INTERN CTILR,CTLRI,CTLRR
INTERN POWC1,POWC2,POWC3
EXTERN PRASE,ZABS,ZBOOL,ZENTIER,ZINT,ZSIGN
EXTERN OPABS,OPENT1,OPENT2,OPENT3,OPJSPX,OPMVMS,OPUMIN
EXTERN OPPSJP,OPSGN1,OPSGN2,OPSGN3,OPSETO
EXTERN OPADDB,OPAOS,OPSOS,OPMVSM
EXTERN OPJMPE,OPJMPG,OPJRST,OPMVLP
EXTERN OPCONC,OPCONV,OPMOVE,OPABS1,OPLNEG
EXTERN OPENT4,OPENT5
SUBTTL COMPILE-TIME TYPE-CONVERSION ROUTINES
;*CTIR INTEGER TO REAL
; CTILR INTEGER TO LONG REAL
;*CTRI REAL TO INTEGER
;*CTRLR REAL TO LONG REAL
; CTLRI LONG REAL TO INTEGER
; CTLRR LONG REAL TO REAL
; ON ENTRY, THE ARGUMENT IS IN A0 OR A0,A1
; THE LINK IS ON THE STACK
; ON EXIT, THE RESULT IS IN A0 OR A0,A1
CTLRI: DFAD A0,[
EXP 0.5,0.0]
HLRZ A2,A0
LSH A2,-11
ANDI A2,000377 ; EXTRACT HIGH ORDER EXPONENT
TLZ A0,377000 ; AND CLEAR IT OUT
JUMPGE A0,.+3 ; NUMBER POSITIVE?
TRC A2,000377 ; NO -- COMPLEMENT EXTRACTED EXPONENT
TLO A0,377000 ; AND SET ALL ONES
SUBI A2,243 ; ADJUST EXPONENT
JUMPG A2,.+3 ; TOO BIG - OVERFLOW
EDIT(006); CORRECT SHIFT
ASHC A0,10(A2) ; [E006] SHIFT MANTISSA TO INTEGER
POPJ SP,
FAIL(128,SOFT,SYM,INTEGER TOO LARGE)
JUMPL A0,CTLRI5 ; NEG ?
HRLOI A0,377777 ; SET LARGEST POSITIVE NUMBER
POPJ SP,
CTLRI5: MOVSI A0,(400000,,0) ; LARGEST NEGATIVE
POPJ SP,
CTILR: ASHC A0,-^D35 ; SHIFT SIGNIFICANCE TO A1
TLC A0,276000 ; JUGGLE THE EXPONENT
DFAD A0,[
EXP 0.0,0.0] ; NORMALIZE
POPJ SP, ; AND RETURN
CTLRR: JUMPGE A0,.+3 ; ARGUMENT POSITIVE?
DMOVN A0,A0 ; NO - NEGATE IT
CTLRRD: TLZA A1,400000 ; AND CLEAR BIT 0 FLAG
CTLRRC: TLO A1,400000 ; YES - SET BIT 0 FLAG
TLNN A1,200000 ; ROUNDING REQUIRED?
JRST CTLRRA ; NO
CAMN A0,[
XWD 377777,777777] ; YES - HIGH WORD TOO LARGE?
JRST CTLRRA ; YES - FORGET IT
ADDI A0,1 ; NO
TLO A0,400 ; CARRY
CTLRRA: JUMPL A1,.+2 ; EXIT IF POSITIVE
MOVN A0,A0 ; OTHERWISE NEGATE
POPJ SP,
SUBTTL POWC1 -- INTEGER TO INTEGER EXPONENTIATION ROUTINE
; ON ENTRY:
; THE BASE IS IN A0
; THE EXPONENT IS IN A2
; THE LINK IS ON THE STACK
; ON EXIT, THE RESULT (INTEGER OR REAL) IS IN A0
POWC1: JUMPN A0,POWC11 ; BASE = 0?
JUMPLE A2,POWCER ; YES. ERROR IF EXPONENT <= 0
POWC10: POPJ SP, ; RESULT = 0 FOR ZERO BASE AND POS. EXP.
POWC11: JUMPL A2,POWC13 ; NEG. EXP. YIELDS REAL RECIPROCAL
MOVE A1,A0 ; COPY BASE
MOVEI A0,1 ; PREPARE FOR MULTIPLICATION
JUMPE A2,POWC10 ; IF EXP. = 0 THEN I^0 = 1
POWC12: TRZE A2,000001 ; BIT SET IN EXPONENT?
IMUL A0,A1 ; YES -- MULTIPLY
JUMPE A2,POWC25 ; EXIT IF FINISHED
IMUL A1,A1 ; OTHERWISE SQUARE MULTIPLIER
LSH A2,-1 ; SHIFT BIT OUT OF EXPONENT
JRST POWC12 ; AND CARRY ON
POWC13: FLTR A0,A0 ; CONVERT INTEGER BASE TO REAL
JRST POWC22 ; COMPUTE REAL POWER
SUBTTL POWC2 -- REAL TO INTEGER EXPONENTIATION ROUTINE
; ON ENTRY:
; THE BASE IS IN A0
; THE EXPONENT IS IN A2
; THE LINK IS ON THE STACK
; ON EXIT, THE RESULT IS IN A0
POWC2: JUMPE A0,POWC24 ; BASE = 0?
JUMPN A2,POWC21 ; NO. EXPONENT = 0?
MOVSI A0,(1.0) ; YES. R^0 = 1.0
POWC20: POPJ SP, ; EXIT
POWC21: CAIG A2,0 ; EXPONENT POSITIVE?
POWC22: TDZA A3,A3 ; NO. CLEAR POSITIVE FLAG AND SKIP
MOVEI A3,1 ; YES. SET POSITIVE FLAG
MOVM A2,A2 ; GET MAGNITUDE OF EXPONENT
MOVE A1,A0 ; COPY BASE
MOVSI A0,(1.0) ; PREPARE FOR "*" (OR "/")
POWC23: TRZE A2,000001 ; BIT SET IN EXPONENT?
XCT [
FDVR A0,A1
FMPR A0,A1](A3) ; YES -- MULTIPLY/DIVIDE
JUMPE A2,POWC25 ; EXIT IF FINISHED
FMPR A1,A1 ; OTHERWISE SQUARE MULTIPLIER
LSH A2,-1 ; SHIFT BIT OUT OF EXPONENT
JRST POWC23 ; AND CARRY ON
POWC24: JUMPG A2,POWC20 ; BASE = 0 -- EXIT IF EXPONENT > 0
POWCER:
FAIL(76,FRIED,SYM,OVERFLOW OR UNDEFINED RESULT FOR "CONSTANT ^ CONSTANT");
POPJ SP, ; ERROR EXIT
POWC25: JFOVO POWCER ; ERROR IF OVERFLOW FLAG ON
POPJ SP, ; NORMAL EXIT
SUBTTL POWC3 -- LONG REAL TO INTEGER EXPONENTIATION ROUTINE
; ON ENTRY:
; THE BASE IS IN (A0,A1)
; THE EXPONENT IS IN A2
; THE LINK IS ON THE STACK
; ON EXIT, THE RESULT (TYPE LONG REAL) IS IN A0,A1
POWC3: JUMPN A0,.+3 ; BASE = 0?
JUMPLE A2,POWCER ; YES - ERROR IF EXP LEQ 0
POPJ SP,
MOVE A3,A0 ; NO -- COPY BASE
MOVE A4,A1
MOVSI A0,(1.0) ; INITIALIZE RESULT TO 1.0&&0
MOVEI A1,0
JUMPN A2,POWC31 ; EXPONENT = 0?
POPJ SP,0 ; YES -- RESULT = 1.0&&0
POWC31: PUSH SP,A6 ; SAVE REGISTERS
PUSH SP,A7
MOVM A7,A2 ; COPY MAGNITUDE OF EXPONENT
JUMPG A2,POWC32 ; EXPONENT POSITIVE?
TDZA A6,A6 ; NO -- CLEAR POSITIVE FLAG
POWC32: MOVEI A6,1 ; YES -- SET POSITIVE FLAG
POWL1: TRZE A7,1 ; STRICTLY KI
XCT [
DFDV A0,A3 ; IF BIT SET IN EXPT, THEN DIVIDE/MULTIPLY
DFMP A0,A3](A6)
JUMPE A7,POWLEX ; ELSE EXIT IF FINISHED
DFMP A3,A3 ; OTHERWISE SQUARE MULTIPLIER
LSH A7,-1 ; SHIFT BIT OUT OF EXPT
JRST POWL1 ; AND CONTINUE
POWLEX: POP SP,A7 ; RESTORE REGISTERS
POP SP,A6
JFOVO POWCER ; ERROR RETURN IF OVERFLOW FLAG ON
POPJ SP,0 ; NORMAL RETURN
SUBTTL CODE GENERATION ROUTINES * CGFUN *
PROCEDURE CGFUN
;..GENERATE CODE FOR CALLS ON STANDARD FUNCTIONS;
; ON ENTRY, FUNCTION LEXEME IS IN LOP;
; ARGUMENT LEXEME IS IN SYM;
; FOR LIBRARY FUNCTIONS, ARGUMENT WILL BE CONVERTED
; TO PROPER TYPE AND LOADED INTO A0.
; IN-LINE CODE WILL BE GENERATED FOR:
; INT
; BOOL
; ABS
; SIGN
; ENTIER
; RESULT IS A CLOSED PORTION WHOSE LEXEME IS IN SYM;
BEGIN
IF SYM IS AN ERROR LEXEME
JUMPGE SYM,FALSE
THEN;..SET ERROR LEXEME AND LEAVE;
ERRLEX;
ELSE;..NO ERRORS YET ..... GO ON;
BEGIN
;..SET REV OFF;
MOVNI REV,SYM
IF LOP IS A LIBRARY FUNCTION
HRRZ T,LOP
CAIGE T,PRASE
GOTO FALSE
THEN;..WE MUST CALL A SUBROUTINE;
BEGIN
IF SYM<TYPE> NEQ ARITHMETIC
TN.ARITH(SYM);
THEN
FAIL(77,FRIED,SYM,NON-ARITHMETIC ARGUMENT FOR STANDARD LIBRARY FUNCTION);
ELSE;..ARGUMENT IS ARITHMETIC;
BEGIN
IF LOP<TYPE> = REAL AND SYM<TYPE> NEQ REAL
TLNN LOP,$TYPE-$R
TN.R (SYM);
THEN;..ARGUMENT MUST BE CONVERTED TO REAL;
;CONVERT(REAL,SYM);
MOVEI T,$R
CONVERT;
ELSE;..LOP HAD BETTER BE LONG REAL;
BEGIN ; [E044]
IF LOP<TYPE> = LONG REAL AND SYM<TYPE> NEQ LONG REAL
TLNN LOP,$TYPE-$LR
TN.LR (SYM);
THEN;..ARGUMENT MUST BE CONVERTED TO LONG REAL;
;CONVERT(LONG REAL,SYM);
MOVEI T,$LR
CONVERT;
FI;
EDIT(044); Dont force constants to D.P. unnecessarily
;.SYM IS LONG REAL - CHECK IF GENUINE ; [E044]
IF SYM = PSEUDO-LONG 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;.MAKE IT A GENUINE LONG REAL CONSTANT; [E044]
MOVE T3,2(T2) ; [E044]
TLZ T4,(1B0) ; [E044]
TOCT (2,SYM) ; [E044]
FI; ; [E044]
ENDD; ; [E044]
FI
IF SYM IS A POINTER
T.PTR (SYM);
THEN;..PUT ITS VALUE INTO A0;
;GO TO NEXT "THEN";
GOTO LCGFN1
FI
IF VALUE OF SYM NOT IN A0
TN.AC0 (SYM);
THEN;..ARGUMENT FOR A LIBRARY FUNCTION MUST BE IN A0;
LCGFN1:
LOAD(SYM,A0);
FI
REOPEN(SYM);
;..GENERATE CALL ON LIBRARY FUNCTION;
IF LOP<TYPE> = LONG REAL
T.LR(LOP);
THEN
MOVSI T,7777
ELSE
MOVSI T,77
FI
IORM T,HANDLE
;PLUNK(PUSHJ,SP,LOP);
MOVE T,OPPSJP
PLUNKI (LOP);
;LEX(SYM) _ (EXPR,SAME,STATEMENT,ACC);
TLZ SYM,$KIND!$STATUS!$AM
TLO SYM,$EXP!$STMT!$ACC
CLOSE(SYM);
ENDD
FI
ENDD
ELSE;..NOT A LIBRARY FUNCTION - MUST BE IN-LINE;
IF LOP = "INT"
CAIE T,ZINT
GOTO FALSE
THEN;..BOOLEAN-TO-INTEGER TRANSFER FUNCTION -- NO CODE GENERATED;
BEGIN
IF SYM<TYPE> NEQ BOOLEAN
TN.B (SYM);
THEN
FAIL(78,FRIED,SYM,NON-BOOLEAN ARGUMENT FOR "INT" FUNCTION);
ELSE;..ARGUMENT IS BOOLEAN. MAKE IT AN INTEGER EXPR;
BEGIN
IF SYM IS A POINTER
T.PTR (SYM);
THEN;..LOAD VALUE INTO SAME ACC USED BY PTR;
F.LOCN (T2,SYM);
LOAD(SYM,@T2);
ELSE;..NOT A POINTER;
IF SYM IS SINGLE
T.SINGLE(SYM);
THEN;..MAKE IT A PORTION IN AN ACC;
LOAD(SYM,ANYAC);
FI
FI
;LEX(SYM) _ (SAME,INTEGER,STATEMENT,SAME);
TLZ SYM,$TYPE!$STATUS
TLO SYM,$I!$STMT
ENDD
FI
ENDD
ELSE;..FUNCTION IS NOT "INT";
IF LOP = "BOOL"
CAIE T,ZBOOL
GOTO FALSE
THEN;..INTEGER-TO-BOOLEAN TRANSFER FUNCTION -- NO CODE GENERATED;
BEGIN
IF SYM<TYPE> NEQ INTEGER
TN.I (SYM);
THEN
FAIL(79,FRIED,SYM,NON-INTEGER ARGUMENT FOR "BOOL" FUNCTION);
ELSE;..ARGUMENT IS INTEGER. MAKE IT A BOOLEAN EXPR;
BEGIN
IF SYM IS A POINTER
T.PTR (SYM);
THEN;..LOAD VALUE INTO SAME ACC USED BY PTR;
F.LOCN (T2,SYM);
LOAD(SYM,@T2);
ELSE;..NOT A POINTER;
IF SYM IS SINGLE
T.SINGLE(SYM);
THEN;..MAKE IT A PORTION IN AN ACC;
LOAD(SYM,ANYAC);
FI
FI
;LEX(SYM) _ (SAME,BOOLEAN,STATEMENT,SAME);
TLZ SYM,$TYPE!$STATUS
TLO SYM,$B!$STMT
ENDD
FI
ENDD
ELSE;..FUNCTION IS NOT "INT" OR "BOOL";
IF SYM<TYPE> NEQ ARITHMETIC
TN.ARITH(SYM);
THEN
FAIL(80,FRIED,SYM,NON-ARITHMETIC ARGUMENT FOR BUILT-IN FUNCTION);
ELSE;..ARGUMENT IS ARITHMETIC;
EDIT(044); Dont force constants to D.P. unnecessarily
BEGIN; ; [E044]
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 IT TO A REAL ; [E044]
MOVE T3,A0 ; [E044]
MOVE A0,2(T2) ; [E044]
MOVE A1,3(T2) ; [E044]
TLZ A1,(1B0) ; [E044]
PUSHJ SP,CTLRR ; [E044]
EXCH T3,A0 ; [E044]
TLZ SYM,$TYPE
TLO SYM,$R
STOCON; ; [E044]
HRRZ T,LOP ; [E044]
FI; ; [E044]
IF LOP = "ABS"
CAIE T,ZABS
GOTO FALSE
THEN;..ABSOLUTE VALUE FUNCTION;
BEGIN
;..RESULT WILL HAVE SAME TYPE AS ARGUMENT
; (TECHNICALLY NOT CORRECT ALGOL 60);
IF SYM<TYPE> = LONG REAL
T.LR (SYM);
THEN;..WE MUST LOAD THE VALUE AND TEST IT;
BEGIN
IF SYM IS A POINTER
T.PTR (SYM);
THEN;..LOAD VALUE INTO SAME ACC USED BY PTR;
F.LOCN (T2,SYM);
LOAD(SYM,@T2);
ELSE;..NOT A POINTER;
IF SYM IS SINGLE
T.SINGLE(SYM);
THEN;..MAKE A PORTION TO LOAD SYM IN AN ACC;
LOAD(SYM,ANYAC);
FI
FI
REOPEN(SYM);
;..EMIT IN-LINE CODE TO TEST SIGN AND NEGATE NEG. VALUE;
;..SKIP THE NEGATION FOR POSITIVE VALUES;
;PLUNK(JUMPGE,SYM,.+2);
MOVE T,OPABS1
F.LOCN (T1,SYM);
PLUNK;
;..NEGATE THE NEGATIVE VALUE;
;PLUNK(LONG NEGATE,SYM,SYM+1);
MOVE T,OPLNEG
F.LOCN (T1,SYM);
MOVE T2,SYM
TLZ T2,777777-$AM
ADD T,T2
PLUNK;
CLOSE(SYM);
ENDD
ELSE;..SYM IS INTEGER OR REAL;
IF SYM IS AN EXPR OR A POINTER IN ACC
T.ACC (SYM);
THEN;..WE ALREADY HAVE A PORTION FOR SYM;
BEGIN
;..APPEND CODE TO GET MAGNITUDE OF SYM;
REOPEN(SYM);
;PLUNK(MABS,SYM,SYM);
MOVE T,OPABS
F.LOCN (T1,SYM);
PLUNK (SYM);
CLOSE(SYM);
ENDD
ELSE;..NO PORTION YET. LOAD MAGNITUDE OF SINGLE ARGUMENT;
;LOADM(SYM,ANYAC);
MOVEI T1,ANYAC
HLL T1,OPMVMS
PUSHJ SP,.LOAD
FI
FI
;LEX(SYM) _ (EXPR,SAME,STATEMENT,ACC);
TLZ SYM,$KIND!$STATUS!$AM
TLO SYM,$EXP!$STMT!$ACC
ENDD
ELSE;..FUNCTION IS NOT "INT" OR "BOOL" OR "ABS";
IF LOP = "SIGN"
CAIE T,ZSIGN
GOTO FALSE
THEN;..SIGN FUNCTION;
BEGIN
IF SYM IS A POINTER
T.PTR (SYM);
THEN;..LOAD VALUE INTO SAME ACC USED BY POINTER;
F.LOCN (T2,SYM);
LOAD(SYM,@T2);
ELSE;..NOT A POINTER;
IF SYM IS SINGLE
T.SINGLE(SYM);
THEN;..MAKE A PORTION TO LOAD SYM INTO AN ACC;
LOAD(SYM,ANYAC);
FI
FI
REOPEN(SYM);
;..EMIT IN-LINE CODE TO COMPUTE "SIGN" FUNCTION;
;..IF ARGUMENT = 0 THEN SIGN(ARG) = 0;
;PLUNK(JUMPE,SYM,.+3);
MOVE T,OPSGN1
F.LOCN (T1,SYM);
PLUNK;
;..SHIFT OUT ALL BUT SIGN BITS (YIELDS 0 OR -1);
;PLUNK(ASH,SYM,-43);
MOVE T,OPSGN2
F.LOCN (T1,SYM);
PLUNK;
;..SET LOW-ORDER BIT TO 1 (YIELDS 1 OR -1);
;PLUNK(TRO,SYM,1);
MOVE T,OPSGN3
F.LOCN (T1,SYM);
PLUNK;
;LEX(SYM) _ (EXPR,INTEGER,STATEMENT,ACC);
TLZ SYM,$KIND!$TYPE!$STATUS!$AM
TLO SYM,$EXP!$I!$STMT!$ACC
CLOSE(SYM);
ENDD
ELSE;..FUNCTION IS NOT "INT" OR "BOOL" OR "ABS" OR "SIGN";
IF LOP = "ENTIER"
CAIE T,ZENTIER
GOTO FALSE
THEN;..LARGEST-INTEGER FUNCTION;
BEGIN
IF SYM<TYPE> = INTEGER
T.I (SYM);
THEN
;CONVERT(REAL,SYM);
MOVEI T,$R
CONVERT;
FI
IF SYM<TYPE> = LONG REAL
T.LR (SYM);
THEN;..LONG REAL ENTIER. CALL SUBROUTINE;
BEGIN
IF SYM IS A POINTER
T.PTR (SYM);
THEN;..MUST GET ITS VALUE;
;GO TO NEXT "THEN";
GOTO LCGFN2
FI
IF VALUE OF SYM NOT IN A0
TN.AC0 (SYM);
THEN;..LOAD IT INTO A0;
LCGFN2:
LOAD(SYM,A0);
FI
REOPEN(SYM);
;..GENERATE INST. TO CALL LONG REAL ENTIER SR;
;PLUNK(JSP,AX,ENTIEL);
MOVE T,OPJSPX
PLUNKI;
;LEX(SYM) _ (EXPR,INTEGER,STATEMENT,ACC);
TLZ SYM,$KIND!$TYPE!$STATUS!$AM
TLO SYM,$EXP!$I!$STMT!$ACC
CLOSE(SYM);
ENDD
ELSE;..ARGUMENT IS REAL. EMIT IN-LINE REAL ENTIER;
BEGIN
;..GIVE SYM SPECIAL TYPE SO LOAD WILL USE 2 ACS;
TLZ SYM,$TYPE
TLO SYM,$IDI
IF SYM IS A POINTER
T.PTR (SYM);
THEN;..MUST GET VALUE OF PTR INTO AN AC;
;..LOAD INTO SAME AC USED FOR PTR;
F.LOCN (T2,SYM);
LOAD (SYM,@T2);
ELSE;..NOT A POINTER;
BEGIN
IF SYM IS SINGLE OR IN LAST AC <AC13>
TLNN SYM,$SINGLE
GOTO TRUE
F.LOCN (T,SYM);
CAIE T,A13
GOTO FALSE
THEN;..MUST MOVE SYM TO A FREE AC PAIR;
LOAD(SYM,ANYAC);
FI
ENDD
FI
IF LAST GENERATED INST. WAS "MOVEI"
MOVE T,INDEX
HLRZ T2,-2(T)
ANDI T2,777000
CAIE T2,<MOVEI 0,0>_-22
GOTO FALSE
THEN;..SYM WAS AN IMMEDIATE REAL CONSTANT;
;.. BUT "LOAD" THOUGHT IT WAS INTEGER;
;..CHANGE INSTRUCTION TO "HRLZI";
MOVE T2,-2(T)
TLZ T2,777000
TLO T2,<HRLZI 0,0>_-22
MOVEM T2,-2(T)
FI
REOPEN(SYM);
;..EMIT IN-LINE CODE TO COMPUTE "ENTIER";
EDIT(031); CAN'T USE FIX OR FIXR, SO DO IT THE HARD WAY
;......SPLIT OFF EXPONENT;
;EMITCODE(MULI,SYM,400,2);
MOVE T,OPENT1
F.LOCN (T1,SYM);
HRLI T1,2
EMITCODE;
;..COMPLEMENT EXPONENT FOR NEGATIVE ARGUMENT;
;PLUNK(TSC,SYM,SYM);
MOVE T,OPENT2
F.LOCN (T1,SYM);
PLUNK (SYM);
;EXCHANGE EXPONENT AND FRACTION;
;PLUNK(EXCH,SYM+1,SYM);
HRLZI T,<EXCH 0,0>_-22
F.LOCN (T1,SYM);
ADDI T1,1
PLUNK (SYM);
;..SHIFT ARGUMENT TO ZERO EXPONENT;
;PLUNK(ASH,SYM<LOCN>,-243(SYM<LOCN>+1));
MOVE T,OPENT3
F.LOCN (T1,SYM);
PLUNK;
;LEX(SYM)_(EXPR,INTEGER,STATEMENT,SYM<LOCN>);
TLZ SYM,$KIND!$TYPE!$STATUS!$AM
TLO SYM,$EXP!$I!$STMT!$ACC
CLOSE(SYM);
ENDD
FI
ENDD
;..ELSE NOT ENTIER;
FI;..IF LOP = ENTIER
FI;..IF LOP = SIGN
FI;..IF LOP = ABS
ENDD;
FI;..IF SYM<TYPE> NEQ ARITHMETIC
FI;..IF LOP = BOOL
FI;.. IF LOP = INT
FI;..IF LOP IS A LIBRARY FUNCTION
ENDD;
FI;..IF SYM IS AN ERROR LEXEME
ENDD ; CGFUN
SUBTTL CODE GENERATION ROUTINES * CGDOT *
PROCEDURE CGDOT
;..GENERATE CODE TO LOAD OPERANDS FOR "DOT" OPERATOR;
; ON ENTRY, LEXEME FOR STRING POINTER IS IN LOP;
; LEXEME FOR INDEX IS IN SYM;
; CODE WILL BE GENERATED TO PUT STRING POINTER INTO A2
; AND INDEX INTO A1;
; RESULT IS A SINGLE CLOSED PORTION WHOSE LEXEME IS IN SYM;
BEGIN
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 SYM = SINGLE
T.SINGLE(SYM);
THEN;..NO PORTION YET FOR SYM;
REOPEN(LOP);
ELSE;..BOTH LOP AND SYM ARE PORTIONS -- JOIN THEM;
BEGIN
REVER;
MERGEPORTIONS;
COMBLEX;
ENDD
FI
IF SYM IN AC2
TLNN SYM,$AMAC
TRNN SYM,2
JRST FALSE
TRNE SYM,-3
JRST FALSE
THEN
BEGIN;..PUSH IT
HRLZI T,(<PUSH SP,0>)
PLUNKI(SYM)
;..SYM<AM> _ SP
TLZ SYM,$AM
TLO SYM,$SP
;..SYM<RHS> _ 0
TRZ SYM,-1
;..SYM<SA> _ SYM<SA> + 1
HRLZI T,1
ADDM T,LEXEX
IF LOP IS ON STACK
T.STK (LOP)
THEN;..ADJUST STACK OFFSET
SUBI LOP,1
FI;
ENDD;
FI;
IF LOP NOT IN AC2
TLNE LOP,$AMAC
GOTO TRUE
HRRZ T,LOP
EDIT(225) ;DELETE IN PROC. CGDOT IN ALGFUN [JBS 4/11/80]
; N.B. IF LOP IS IN AC0, ADDRESS IS IN AC2;
CAIN T,A2
GOTO FALSE
THEN;..PUT IT INTO AC2;
BEGIN
;..FUDGE MODE TO MOVE POINTER ITSELF (NOT @PTR);
IF LOP IS ON THE STACK
T.STK (LOP);
THEN;..FUDGE AS STACKED EXPRESSION;
TLZ LOP,$AM
TLO LOP,$SP
ELSE;..FUDGE AS EXPRESSION IN ACC;
TLZ LOP,$AM
TLO LOP,$ACC
FI
;PLUNK(MOVE,AC2,LOP);
MOVE T,OPMOVE
MOVEI T1,A2
PLUNK (LOP);
ENDD
FI
IF SYM NOT IN AC1
TLNE SYM,$AMAC
GOTO TRUE
HRRZ T,SYM
CAIN T,A1
GOTO FALSE
THEN;..PUT IT INTO AC1;
MOVE T,OPMVSM
MOVEI T1,A1
GLOAD;
FI
;LEX(SYM) _ (VAR,STRING,REGULAR,PTR,AC2);
TLZ SYM,$KIND!$TYPE!$STATUS!$AM
TLO SYM,$VAR!$S!$REG!$PTR
HRRI SYM,A2
CLOSE(SYM);
ENDD
FI
ENDD ; CGDOT
SUBTTL CODE GENERATION ROUTINES * CGFTEST *
PROCEDURE CGFTEST
;..GENERATE CODE FOR THE "STEP-UNTIL" TEST IN A "FOR" STATEMENT
; ON ENTRY, LEXEME FOR CONTROLLED VARIABLE IS IN LOP;
; LEXEME FOR FINAL VALUE IS IN SYM;
; LEXEME FOR INCREMENT IS IN FBSYMSAVE;
; IF INCREMENT = CONSTANT, ITS SIGN WILL NOT BE
; TESTED AT RUN TIME.
; IF INCREMENT NEQ CONSTANT, THE GENERAL ALGOL TEST
; SEQUENCE WILL BE GENERATED;
; RESULT IS A CLOSED PORTION WHOSE LEXEME IS IN SYM;
BEGIN
IF LOP IS AN ERROR LEXEME
JUMPGE LOP,FALSE
THEN;..SET ERROR LEXEME AND LEAVE;
ERRLEX;
ELSE;..LOP IS OK;
IF INCREMENT IS AN ERROR LEXEME
MOVE T,FBSYMSAVE
JUMPGE T,FALSE
THEN;..SET ERROR LEXEME AND LEAVE;
ERRLEX;
ELSE;..NO ERRORS YET ..... GO ON;
BEGIN
;..SET REV OFF;
MOVNI REV,SYM
;..PUT INCREMENT LEXEME INTO A REGISTER;
MOVE T2,FBSYMSAVE
IF INCREMENT IS CONSTANT
T.CONST (T2);
THEN;..CONSTANT INCREMENT. NO NEED TO TEST IT ON EACH CYCLE;
BEGIN
;..PUT VALUE OF INCREMENT IN T3;
IF INCREMENT = IMMEDIATE CONSTANT
T.IMM (T2);
THEN;..IMMEDIATE CONSTANT;
BEGIN
IF INCREMENT<TYPE> = INTEGER
T.I (T2);
THEN;..IMMEDIATE INTEGER CONSTANT;
;..RH(T3) _ INCREMENT<LOCN>;
HRRZ T3,T2
ELSE;..IMMEDIATE REAL CONSTANT;
;..LH(T3) _ INCREMENT<LOCN>;
HRLZ T3,T2
FI
ENDD
ELSE;..NON-IMMEDIATE CONSTANT;
BEGIN
;T1 _ INCREMENT<LOCN> + CONSTANT TABLE BASE;
F.LOCN (T1,T2);
ADD T1,CONTAB
IF INCREMENT<TYPE> = LONG REAL
T.LR (T2);
THEN;..GET FIRST WORD OF LONG REAL CONSTANT;
MOVE T3,2(T1)
ELSE;..GET REAL OR INTEGER CONSTANT;
MOVE T3,1(T1)
FI
ENDD
FI
;..VALUE OF CONSTANT IS NOW IN T3. TEST ITS SIGN;
EDIT(046); Do the correct thing for a zero increment
IF CONSTANT GEQ 0
JUMPL T3,FALSE ; [E046]
THEN;..CONSTANT >= 0. NORMAL TEST ; [E046]
MOVE T,ZLEQ
ELSE;..CONSTANT < 0. REVERSE THE TEST ; [E046]
MOVE T,ZGTE
FI
MOVEM T,OP
;..GENERATE CODE FOR THE RELATION. IF THE INCREMENT
;.. IS GREATER THAN 0, THE TEST WILL BE:
;.. IF CONT.VAR. > FINAL VAL. THEN GO TO ELM.-EXH.;
;.. OTHERWISE THE TEST WILL BE
;.. IF CONT.VAR. < FINAL VAL. THEN GO TO ELM.-EXH.;
CGBIN;
;..NOW BACK UP THE STACK POINTER;
UNSTACK;
;..NOW PUT IN THE JUMP TO "ELEMENT-EXHAUSTED";
REOPEN(SYM);
IF THE LAST GENERATED INSTRUCTION = "SETO"
MOVE T,INDEX
HLLZ T1,-1(T)
TLZ T1,000777
CAME T1,OPSETO
GOTO FALSE
THEN;..NOTHING WAS STACKED. NO NEED TO GENERATE "TRUE" OR "FALSE";
BEGIN
;..REPLACE THE "TDZA" AND "SETO" BY A "JRST";
;INDEX _ INDEX - 2;
SUBI T,2
MOVEM T,INDEX
;PLUNK(JRST,0,0);
MOVE T,OPJRST
PLUNKI;
ENDD
ELSE;..CAN'T BACK UP - "UNSTACK" PUT IN AN INSTRUCTION;
;..APPEND A JUMPE;
;PLUNK(JUMPE,SYM,0);
HLLZ T,-2(T)
TLZ T,777000
TDO T,OPJMPE
F.LOCN (T1,SYM);
PLUNKI;
FI
ENDD
ELSE;..INCREMENT IS NOT CONSTANT. MUST GENERATE THE GENERAL TEST;
BEGIN
;..TEST WILL BE
;.. IF (CONTR. VAR. - FINAL VALUE)*SIGN(INCREMENT) > 0
;.. THEN GO TO ELEMENT-EXHAUSTED;
;..
;..GENERATE CODE FOR (CONTR. VAR. - FINAL VALUE);
MOVE T,ZMINUS
MOVEM T,OP
CGBIN;
;..LOP _ LEXEME AND LEXEX FOR (CONT. VAR. - FINAL VALUE);
MOVE LOP,SYM
MOVE T,LEXEX
MOVEM T,LLEXEX
MOVE T,LEXEX+1
MOVEM T,LLEXEX+1
;..SYM _ LEXEME AND LEXEX FOR INCREMENT;
MOVE SYM,FBSYMSAVE
MOVE T,FBLEXSAVE
MOVEM T,LEXEX
MOVE T,FBCOMPSAVE
MOVEM T,LEXEX+1
;..GENERATE CODE FOR MULTIPLICATION BY SIGN OF INCREMENT;
;..SET OP THOROUGHLY NON-REVERSIBLE;
MOVEI T,0
MOVEM T,OP
SETUP
;PLANT <SKIPGE SYM>
HRLZI T,(<SKIPGE>)
PLUNKI(SYM)
IF LOP<TYPE> IS LONG.REAL;
T.LR (LOP)
THEN;..PLANT(LMOVN,LOP);
MOVE T,OPLNEG
ELSE;..PLANT(MOVN,LOP);
MOVE T,OPUMIN
FI;
F.LOCN (T1,LOP)
PLUNK(LOP)
CLOSE(SYM);
COMBLEX;
;..MAKE SURE THE STACK POINTER IS RESET;
UNSTACK;
;..NOW APPEND THE TEST WHICH JUMPS TO "ELEMENT-EXHAUSTED";
REOPEN(SYM);
;PLUNK(JUMPG,LOP,0);
MOVE T1,INDEX
HLLZ T,-1(T1)
TLZ T,000037
CAMN T,[SUB SP,0]
HLLZ T,-2(T1)
TLZ T,777037
TDO T,OPJMPG
F.LOCN (T1,LOP);
PLUNK;
ENDD
FI
CLOSE(SYM);
ENDD
FI
FI
ENDD ; CGFTEST
SUBTTL CODE GENERATION ROUTINES * CGINCR *
PROCEDURE CGINCR
;..GENERATE EFFICIENT CODE FOR INCREMENTING A CONTROLLED VARIABLE;
; ON ENTRY, LEXEME FOR CONTROLLED VARIABLE IS IN LOP;
; LEXEME FOR INCREMENT IS IN SYM;
; NUMBER OF PREFERRED ACC IS IN PREFACC;
; IF INCREMENT = 1 THEN CODE IS "AOS"
; ELSE IF INCREMENT = -1 THEN CODE IS "SOS"
; ELSE IF INCREMENT = 0 THEN CODE IS "MOVE"
; ELSE CODE IS "ADDB";
; CLOSED PORTION FOR ASSIGNMENT OF INCREMENTED VALUE
; IS GENERATED AND ITS RESULT LEXEME IS PUT IN SYM;
BEGIN
IF LOP IS AN ERROR LEXEME
JUMPGE LOP,FALSE
THEN;..SET ERROR LEXEME AND LEAVE;
ERRLEX;
ELSE;..LOP IS OK;
IF INCREMENT IS AN ERROR LEXEME
JUMPGE SYM,FALSE
THEN;..SET ERROR LEXEME AND LEAVE;
ERRLEX;
ELSE;..NO ERRORS YET ..... GO ON;
BEGIN
;..SET REV OFF;
MOVNI REV,SYM
EDIT(046); Don't generate an "ADDB" for a zero increment !
IF SYM IS A CONSTANT WITH VALUE ZERO ; [E046]
T.CONST (SYM) ; [E046]
F.LOCN (T,SYM) ; [E046]
TLNN SYM,$AM-$IMM ; [E046]
JRST .+3 ; [E046]
ADD T,CONTAB ; [E046]
MOVE T,1(T) ; [E046]
JUMPN T,FALSE ; [E046]
THEN;..NO NEED TO GENERATE AN ADDB ; [E046]
MOVE T4,OPMOVE ; [E046]
GOTO LCGIN0 ; [E046]
FI; ; [E046]
IF LOP<TYPE> = INTEGER
T.I (LOP);
THEN;..LOP AND SYM ARE BOTH OF TYPE INTEGER;
BEGIN
IF VALUE OF INCREMENT = 1
F.LOCN (T,SYM);
CAIN T,1
TLNE SYM,$AM-$IMM
GOTO FALSE
THEN;..INCREMENT = 1. DO THE INCREMENT WITH AN "AOS";
;OPN _ "AOS";
MOVE T4,OPAOS
ELSE;..INCREMENT IS NOT 1;
IF VALUE OF INCREMENT = -1
TLNN SYM,$AM-$CT
TLNN SYM,$CT-$IMM
GOTO FALSE
F.LOCN (T2,SYM);
ADD T2,CONTAB
MOVN T,1(T2)
CAIE T,1
GOTO FALSE
THEN;..INCREMENT = -1. DO THE INCREMENT WITH A "SOS";
;OPN _ "SOS";
MOVE T4,OPSOS
ELSE;..INCREMENT IS NOT 1;
;..GO TO CODE WHICH LOADS INCREMENT INTO AN ACC;
GOTO LCGIN1
FI
FI
LCGIN0: ; [E046] LABEL ADDED FOR ZERO CONSTANTS
IF LOP IS NOT SINGLE
TN.SINGLE(LOP);
THEN;..WE ALREADY HAVE A PORTION FOR LOP;
REOPEN(LOP);
FI
IF PREFACC = 0
SKIPE 0,PREFACC
GOTO FALSE
THEN;..CAN'T AOS OR SOS INTO AC0. CHANGE IT TO AC1
; [E046] UNLESS OPCODE = MOVE, WHEN AC0 IS O.K.
TLNE T4,174000 ; [E046]
AOS 0,PREFACC
FI
;EMITCODE(OPN,PREFACC,LOP);
MOVE T,T4
MOVE T1,PREFACC
HRLI T1,1
EMITCODE(LOP);
;LEX(SYM) _ (EXPR,SAME,SIMPLE,PREFACC);
TLZ SYM,$KIND!$STATUS!$AM
TLO SYM,$EXP!$SIM!$ACC
HRR SYM,PREFACC
ENDD
ELSE;..LOP<TYPE> MUST BE REAL;
BEGIN
IF SYM<TYPE> = INTEGER
T.I (SYM);
THEN;..CONVERT SYM TO REAL;
;CONVERT(REAL,SYM);
MOVEI T,$R
CONVERT;
FI
LCGIN1:
IF SYM IS A POINTER
T.PTR (SYM);
THEN;..MUST LOAD ITS VALUE;
;GO TO NEXT "THEN";
GOTO LCGIN2
FI
IF SYM = SINGLE
T.SINGLE(SYM);
THEN;..INCREMENT IS NOT YET IN AN ACC. LOAD IT;
LCGIN2:
;..LOAD INCREMENT INTO PREFERRED REGISTER (GIVEN BY PREFACC);
MOVE T2,PREFACC
LOAD(SYM,@T2);
ELSE;..VALUE OF INCREMENT IS ALREADY IN AN ACC;
IF SYM<LOCN> = LOP<LOCN>
F.LOCN (T,SYM);
F.LOCN (T1,LOP);
CAMN T,T1
TLNE LOP,$AMAC
GOTO FALSE
THEN;..ACC CONFLICT. RELOAD INCREMENT INTO PREFERRED ACC;
GOTO LCGIN2
FI
FI
IF LOP = SINGLE
T.SINGLE(LOP);
THEN;..NO PORTION NEEDED FOR LOP;
REOPEN(SYM);
ELSE;..BOTH LOP AND SYM ARE PORTIONS;
MERGEPORTIONS;
FI
;..GENERATE AN ADD-TO-BOTH;
F.TRANK (T,SYM);
MOVE T,OPADDB(T)
F.LOCN (T1,SYM);
PLUNK (LOP);
;LEX(SYM) _ (EXPR,SAME,SIMPLE,ACC);
TLZ SYM,$KIND!$STATUS!$AM
TLO SYM,$EXP!$SIM!$ACC
ENDD
FI
CLOSE(SYM);
COMBASSIGN;
ENDD
FI
FI
ENDD ; CGINCR
SUBTTL CODE GENERATION ROUTINES * CHECKARITH *
PROCEDURE CHECKARITH;
;..FORCE BINARY OPERANDS TO HAVE MATCHING ARITHMETIC TYPES;
; ERROR FLAG (T) IS SET IF TYPES ARE NOT ARITHMETIC
; (INTEGER OR REAL OR LONG REAL);
; ON ENTRY, OPERAND LEXEMES ARE IN LOP AND SYM.
; IF TYPES OF OPERANDS ARE NOT ALIKE, CODE IS GENERATED TO
; CONVERT ONE OPERAND TO THE TYPE OF THE OTHER
; (IN THE ORDER INTEGER => REAL => LONG REAL).
; OPERAND PORTIONS ARE LEFT CLOSED WITH LEXEMES
; IN LOP AND SYM.
BEGIN
IF SYM<TYPE> IS INT OR REAL OR LONG REAL
; AND LOP<TYPE> IS INT OR REAL OR LONG REAL;
TLNE SYM,$IRLR
T.IRLR (LOP);
THEN;..OPERANDS HAVE TYPES WHICH CAN BE MATCHED;
BEGIN
IF SYM<TYPE> NEQ LOP<TYPE>
F.TYPE (T,SYM);
F.TYPE (T1,LOP);
CAMN T,T1
GOTO FALSE
THEN;..TYPES DO NOT MATCH -- GENERATE CODE TO MATCH THEM;
BEGIN
IF SYM<TYPE> LSS LOP<TYPE>
CAML T,T1
GOTO FALSE
THEN
;..CONVERT SYM TO THE TYPE OF LOP;
PUSHJ SP,TCHECK ; [E044]
ELSE
;..CONVERT LOP TO THE TYPE OF SYM;
;..MUST REVERSE LEXEMES AND LEXEXES BECAUSE CONVERT WORKS ON SYM;
EXCH LOP,SYM
MOVNI REV,SYM+LOP(REV)
PUSHJ SP,TCHECK ; [E044]
EXCH SYM,LOP
MOVNI REV,SYM+LOP(REV)
FI;
ENDD;
FI;
EDIT(044);Don't force constants to D.P. unnecessarily
; TYPES MATCH - CHECK FOR PSEUDO-LONG REAL ; [E044]
IF TYPE = LONG REAL ; [E044]
T.LR (SYM) ; [E044]
THEN; ; [E044]
BEGIN; ; [E044]
IF SYM = PSEUDO-LONG REAL CONSTANT & LOP # CONSTANT
TLNE LOP,$CONST ; [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
MOVE T3,2(T2) ; [E044]
TLZ T4,(1B0) ; [E044]
TOCT (2,SYM) ; [E044]
ELSE; ; [E044]
BEGIN; ; [E044]
IF LOP = PSEUDO-LONG REAL CONSTANT & SYM # CONSTANT
TLNE SYM,$CONST ; [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;..CONVERT LOP TO A GENUINE LONG REAL CONSTANT
MOVE T3,2(T2) ; [E044]
TLZ T4,(1B0) ; [E044]
TOCT (2,LOP) ; [E044]
FI; ; [E044]
ENDD; ; [E044]
FI; ; [E044]
ENDD; ; [E044]
FI; ; [E044]
;T_FALSE ; TURN ERROR FLAG OFF
SETZ T,0
ENDD;
ELSE;..TYPES CANNOT BE MATCHED;
;T_TRUE ; SET ERROR FLAG ON
SETO T,0
FI;
ENDD ; CHECKARITH
TCHECK: Edit(044) ;New routine to match type of SYM to LOP
BEGIN; ; [E044]
IF LOP = PSEUDO-LONG CONSTANT & SYM # CONSTANT ; [E044]
TLNN LOP,<$TYPE-$LR>!$CONST;
TLNN SYM,$CONST ; [E044]
GOTO FALSE ; [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; FIRST WE MUST TRUNCATE LOP TO A REAL ; [E044]
MOVE T3,A0 ; [E044]
MOVE A0,2(T2) ; [E044]
TLZ A1,(1B0) ; [E044]
PUSHJ SP,CTLRR ; [E044]
EXCH T3,A0 ; [E044]
TLZ LOP,$TYPE ; [E044]
TLO LOP,$R ; [E044]
EXCH LOP,SYM ; [E044]
PUSHJ SP,.STOCON ; [E044]
EXCH LOP,SYM ; [E044]
; IF SYM<TYPE> # REAL, SKIP INTO THE "ELSE" CLAUSE ; [E044]
TLNN SYM,$TYPE-$R ; [E044]
ELSE; WE NEED TO CONVERT SYM TO THE TYPE OF LOP ; [E044]
HLRZ T,LOP ; [E044]
ANDI T,$TYPE ; [E044]
PUSHJ SP,.CONVERT ; [E044]
FI; ; [E044]
POPJ SP, ; [E044]
ENDD; TCHECK ; [E044]
SUBTTL CODE GENERATION ROUTINES * COMBASSIGN *
PROCEDURE COMBASSIGN;
;..GENERATE THE NEW LEXEX RESULTING FROM AN ASSIGNMENT;
; NEW LEXEX COMES FROM THOSE FOR SYM AND LOP.
; COMPUTES EXTYPE, BLOCK LEVEL, STACK ADDRESS, AND
; COMPOSITE NAME FOR THE ASSIGNMENT EXPRESSION.
; RESULT LEXEX IS ALWAYS THAT BELONGING TO SYM;
BEGIN
IF LEXEX(SYM) GEQ 0
F.BL (T1,SYM);
JUMPL T1,FALSE
THEN;..SYM HAS EXTYPE "V". SET IT TO "P" AND SET C.N. _ 0;
BEGIN
;SYM<BLOCK LEVEL> _ -1 (I.E., EXTYPE _ "P");
HRLZI T2,777000
S.BL (T2);
;SYM<COMPOSITE NAME> _ 0;
SETZ T2,0
S.CN (T2);
ENDD
FI
;SYM<COMPOSITE NAME> _ SYM<C. NAME> OR LOP<C. NAME>;
F.CN (T2,LOP);
F.CN (T1,SYM);
OR T2,T1
S.CN (T2);
;..BLOCK LEVEL _ MIN(BLOCK LEVELS); .... (SETS EXTYPE ALSO);
IF LOP<BLOCK LEVEL> LSS SYM<BLOCK LEVEL>
F.BL (T3,LOP);
F.BL (T2,SYM);
CAML T3,T2
GOTO FALSE
THEN
;SYM<BLOCK LEVEL> _ LOP<BLOCK LEVEL>;
S.BL (T3);
FI
;..STACK ADDRESS _ SUM OF STACK ADDRESSES;
;T2 _ LOP<STACK ADDRESS> + SYM<STACK ADDRESS>;
F.SA (T2,LOP);
F.SA (T1,SYM);
ADD T2,T1
IF STACK ADDRESS GEQ 2^9 (512)
TLNN T2,$LEXBL
GOTO FALSE
THEN;..STACK OVERFLOW ERROR;
FAIL(66,FRIED,SYM,STACK-ADDRESS OVERFLOW);
ELSE;..SYM<STACK ADDRESS> _ T2;
S.SA (T2);
FI
ENDD ; COMBASSIGN
SUBTTL CODE GENERATION ROUTINES * COMBLEX *
PROCEDURE COMBLEX
;..GENERATE THE NEW LEXEX RESULTING FROM A BINARY OPERATION;
; NEW LEXEX COMES FROM THOSE FOR SYM AND LOP.
; COMPUTES EXTYPE, BLOCK LEVEL, STACK ADDRESS, AND
; COMPOSITE NAME FOR THE RESULT EXPRESSION.
; RESULT LEXEX IS ALWAYS THAT BELONGING TO SYM;
BEGIN
IF EXTYPE(LOP) = EXTYPE(SYM)
F.BL (T3,LOP);
F.BL (T2,SYM);
MOVE T,T2
XOR T,T3
JUMPL T,FALSE
THEN;..EXTYPES MATCH (BOTH "P" OR BOTH "V");
;SYM<COMPOSITE NAME> _ LOP<C. NAME> OR SYM<C. NAME>;
F.CN (T1,LOP);
F.CN (T,SYM);
OR T,T1
S.CN (T);
ELSE;..EXTYPES DO NOT MATCH. RESULT GETS C.N. OF TYPE "P" LEXEME;
IF LOP<LEXEX> LSS 0
JUMPGE T3,FALSE
THEN;..LOP HAS EXTYPE "P". GRAB ITS C. NAME FOR THE RESULT;
;SYM<COMPOSITE NAME> _ LOP<C. NAME>;
F.CN (T,LOP);
S.CN (T);
;..ELSE SYM HAS EXTYPE "P" AND ITS C.N. IS THAT OF THE RESULT;
FI
FI
;..BLOCK LEVEL _ MIN(BLOCK LEVELS); .... (SETS EXTYPE ALSO);
IF LOP<BLOCK LEVEL> LSS SYM<BLOCK LEVEL>
CAML T3,T2
GOTO FALSE
THEN
;SYM<BLOCK LEVEL> _ LOP<BLOCK LEVEL>;
S.BL (T3);
FI
;..STACK ADDRESS _ SUM OF STACK ADDRESSES;
;T2 _ LOP<STACK ADDRESS> + SYM<STACK ADDRESS>;
F.SA (T2,LOP);
F.SA (T1,SYM);
ADD T2,T1
IF STACK ADDRESS GEQ 2^9 (512)
TLNN T2,$LEXBL
GOTO FALSE
THEN;..STACK OVERFLOW ERROR;
FAIL(66,FRIED,SYM,STACK-ADDRESS OVERFLOW);
ELSE;..SYM<STACK ADDRESS> _ T2;
S.SA (T2);
FI
ENDD ; COMBLEX
SUBTTL CODE GENERATION ROUTINES * CONVERT *
PROCEDURE CONVERT
;..GENERATES CODE TO CONVERT AN OPERAND TO A GIVEN TYPE;
; ON ENTRY, OPERAND LEXEME IS IN SYM;
; DESIRED TYPE IS IN T;
; IF OPERAND IS A CONSTANT, A NEW CONSTANT WILL BE GENERATED
; (AND NO CODE WILL BE PRODUCED).
; RESULT IS A CLOSED PORTION WHOSE LEXEME IS IN SYM;
BEGIN
OWN RESTYPE; ;..TEMP FOR THE DESIRED TYPE BITS;
;RESTYPE _ T;
MOVEM T,RESTYPE
IF SYM = CONSTANT
T.CONST (SYM);
THEN;..OPERAND IS A CONSTANT. WE CAN DO THE CONVERSION RIGHT NOW;
BEGIN
;..SAVE A0 (GBREG);
MOVE T3,A0
IF SYM = IMMEDIATE
T.IMM (SYM);
THEN;..IMMEDIATE CONSTANT. PUT VALUE INTO A0;
BEGIN
IF SYM<TYPE> = INTEGER
T.I (SYM);
THEN
;RH(A0) _ SYM<LOCN>;
HRRZ A0,SYM
ELSE;..IMMEDIATE REAL CONSTANT;
;LH(A0) _ SYM<LOCN>;
HRLZ A0,SYM
FI
ENDD
ELSE;..NON-IMMEDIATE CONSTANT;
BEGIN
;T2 _ SYM<LOCN> + CONSTANT TABLE BASE;
F.LOCN (T2,SYM);
ADD T2,CONTAB
IF SYM<TYPE> = LONG REAL
T.LR (SYM);
THEN;..LONG CONSTANT;
;..PUT CONSTANT INTO A0 AND A1;
;.. * * * NOTE THAT A1 IS THE SAME REGISTER AS T;
DMOVE A0,2(T2)
TLZ A1,(1B0) ; [E044]
ELSE;..SHORT CONSTANT;
;..PUT CONSTANT INTO A0;
MOVE A0,1(T2)
FI
ENDD
FI
;..EXECUTE APPROPRIATE CONVERSION ROUTINE (RESULT GOES TO A0 (AND A1));
;.. * * * NOTE THAT A2 (T1) MAY BE CLOBBERED HERE;
MOVE T2,RESTYPE
LSH T2,-14
F.TRANK (T1,SYM);
LSH T1,2
OR T2,T1
XCT OPCONC-1(T2)
;LEX(SYM) _ (SAME,RESTYPE,SAME,SAME);
TLZ SYM,$TYPE
TSO SYM,RESTYPE
;..WE NOW HAVE A NEW OPERAND. IT MUST BE PUT IN THE CONSTANT TABLE;
;..MOVE HIGH ORDER WORD OF CONSTANT TO T3 AND RESTORE A0;
EXCH T3,A0
IF SYM<TYPE> = LONG REAL
T.LR (SYM);
THEN;..LONG REAL CONSTANT;
BEGIN
;..MOVE LOW ORDER WORD OF CONSTANT TO T4;
MOVE T4,A1
TLO T4,(1B0) ; [E044]
;..PUT IN CONSTANT TABLE (T3,T4);
TOCT(2,SYM);
ENDD
ELSE;..SHORT CONSTANT;
STOCON;
FI
ENDD
ELSE;..OPERAND IS NOT A CONSTANT;
BEGIN
;..OPERAND MUST BE IN AC0 (AND 1) FOR THE CONVERSION ROUTINES;
IF SYM IS A POINTER
T.PTR (SYM);
THEN;..LOAD ITS VALUE INTO AC0;
GOTO LCONV1
FI
IF VALUE OF SYM NOT IN AC0
TN.AC0 (SYM);
THEN;..PUT IT IN;
LCONV1:
;..GENERATE CODE TO MOVE OPERAND TO AC0 (AND 1);
LOAD(SYM,A0);
FI
REOPEN(SYM);
;..GENERATE CALL ON CONVERSION SUBROUTINE;
;PLUNKI(CONVERTOP);
MOVE T1,RESTYPE
LSH T1,-14
F.TRANK (T,SYM);
LSH T,2
OR T,T1
MOVE T,OPCONV-1(T)
PLUNKI;
;..BOOK A1 IN HANDLE
HRLZI T,2
IORM T,HANDLE
;LEX(SYM) _ (EXPR,RESTYPE,SIMPLE,AC0);
TLZ SYM,$KIND!$TYPE!$STATUS!$AM
TSO SYM,RESTYPE
TLO SYM,$EXP!$SIM!$ACC
HRRI SYM,0
CLOSE(SYM);
ENDD
FI
ENDD ; CONVERT
SUBTTL CODE GENERATION ROUTINES * MARRY *
PROCEDURE MARRY
;..MAKE A SINGLE OPEN PORTION FOR TWO BINARY OPERANDS,
; REVERSING THE ORDER IF POSSIBLE;
; ON ENTRY, LEXEMES FOR THE OPERANDS ARE IN LOP AND SYM;
; UNLESS THE OPERATION = "^", MARRY WILL MAKE SURE THAT
; THE RESULT PORTION INCLUDES CODE TO LOAD
; THE "LEFT" OPERAND INTO AN AC;
BEGIN
IF SYM = SINGLE
T.SINGLE(SYM);
THEN;..SYM IS NOT A PORTION;
BEGIN
IF LOP NEQ SINGLE
TN.SINGLE(LOP);
THEN;..LOP IS A PORTION AND SYM IS NOT;
REOPEN(LOP);
ELSE;..BOTH LOP AND SYM ARE SINGLE;
BEGIN
IF OP NEQ "^"
TN.OPER (ZPOW);
THEN;..MAKE A PORTION TO PUT A VALUE IN AN ACC;
BEGIN
IF LOP = ONE-WORD CONSTANT AND OP IS REVERSIBLE
TLNN LOP,$VAR1
T.CONST (LOP);
TRNN T,$ODROP
GOTO FALSE
THEN;..REVERSE THE ORDER SO VARIABLE IS LOADED FIRST;
BEGIN
;..EXCHANGE THE LEXEMES;
EXCH LOP,SYM
;..SET REV ON;
MOVNI REV,LOP
ENDD
FI
LOAD(LOP,ANYAC);
REOPEN(LOP);
ENDD
;..ELSE NO PORTIONS ARE NECESSARY FOR POWERS;
FI
ENDD
FI
ENDD
ELSE;..SYM IS A PORTION;
BEGIN
REVORDER;
IF LOP = SINGLE
T.SINGLE(LOP);
THEN;..AFTER REORDERING, LOP IS STILL NOT A PORTION.
;..MAKE IT ONE AND MERGE WITH SYM;
BEGIN
LOAD(LOP,ANYAC);
MERGEPORTIONS;
ENDD
ELSE;..LOP IS A PORTION AFTER REORDERING;
IF SYM = SINGLE
T.SINGLE(SYM);
THEN;..THERE IS ONLY ONE PORTION;
REOPEN(LOP);
ELSE;..TWO PORTIONS;
BEGIN
IF LOP IS A POINTER
T.PTR (LOP);
THEN;..WE MAY HAVE TO EVALUATE LOP BEFORE MERGING;
BEGIN
IF REVERSAL NOT ALLOWED OR LOP IS A ONE WORD OPERAND
JUMPN T3,TRUE
;..(T3 IS A SWITCH WHICH IS SET BY REVORDER);
T.ONE (LOP);
THEN;..EVALUATE LOP NOW;
;..LOAD VALUE OF LOP INTO SAME ACC USED BY POINTER;
F.LOCN (T2,LOP);
LOAD(LOP,@T2);
FI
ENDD
FI
MERGEPORTIONS;
ENDD
FI
FI
ENDD
FI
ENDD ; MARRY
SUBTTL CODE GENERATION ROUTINES * SETUP *
PROCEDURE SETUP
;..SET UP THE OPERANDS FOR A BINARY OPERATION BY
; MAKING A SINGLE OPEN PORTION, REORDERED IF POSSIBLE,
; WITH THE VALUE OF THE (REORDERED) LEFT OPD (LOP) IN AN AC;
; ON ENTRY, OPERAND LEXEMES ARE IN LOP AND SYM;
; SETUP MAY CHANGE THE OPERATOR IF THE OPERATION
; IS REVERSIBLE, (E.G., "<" => ">", LFDV => RLFDV).
BEGIN
;..FIRST MAKE A SINGLE OPEN PORTION FOR THE OPERANDS;
MARRY;
IF REV
T.REV;
THEN;..PORTIONS WERE REVERSED BY MARRY;
BEGIN
;..EXCHANGE THE LEXEMES AGAIN;
EXCH LOP,SYM
;..SET REV OFF;
MOVNI REV,SYM
ENDD
FI
IF LOP NOT AN EXPRESSION IN ACC
TN.ACC (LOP);
THEN;..VALUE OF LOP IS NOT NOW IN AN AC;
BEGIN
IF VALUE OF SYM IN AN ACC
TLNE SYM,$AM-$ACC
GOTO FALSE
THEN;..WE MAY BE ABLE TO DO AN OPERATOR REVERSAL;
BEGIN
IF OP IS NOT REVERSIBLE
MOVE T,OP
TRNE T,$ODROP
GOTO FALSE
THEN;..OP IS NOT USUALLY REVERSIBLE;
BEGIN
IF SYM<TYPE> = LONG REAL
T.LR (SYM);
THEN;..OPERANDS ARE LONG REAL;
BEGIN
IF OP = SLASH
T.OPER (ZSLASH);
THEN;..WE CAN CALL A REVERSE DIVIDE SR;
GOTO LSETU1
FI
IF OP = "-"
T.OPER (ZMINUS);
THEN;..WE CAN CALL A REVERSE SUBTRACT SR;
GOTO LSETU1
FI
ENDD
FI
;..NO CHANCE OF OPERATOR REVERSAL. LOAD VALUE OF LOP INTO AN AC;
GOTO LSETU2
ENDD
ELSE;..OP IS REVERSIBLE;
BEGIN
LSETU3:
IF OP IS NOT COMMUTATIVE
MOVE T,OP
TRNE T,$ODCOP
GOTO FALSE
THEN;..MAKE OP INTO ITS REVERSE;
LSETU1:
;..OP _ REVERSE(OP);
MOVE T,OP
ADDI T,2_^D8
MOVEM T,OP
;..ELSE COMMUTATIVE OP IS ITS OWN REVERSE;
FI
;..REVERSE THE OPERANDS BY EXCHANGING LEXEMES AND LEXEXES;
MOVE T,LEXEX
EXCH T,LEXEX+2
MOVEM T,LEXEX
MOVE T,LEXEX+1
EXCH T,LEXEX+3
MOVEM T,LEXEX+1
EXCH LOP,SYM
ENDD
FI
ENDD
ELSE;..NEITHER SYM NOR LOP HAS A LOADED VALUE;
BEGIN
IF LOP = SINGLE AND SYM = POINTER AND OP IS REVERSIBLE
T.PTR (SYM);
MOVE T,OP
TRNE T,$ODROP
TLNE LOP,$SINGLE
GOTO FALSE
THEN;..WE SHOULD LOAD THE VALUE OF SYM NOW;
BEGIN
;..LOAD VALUE OF SYM INTO SAME ACC, LEAVING PORTION OPEN;
MOVE T,OPMVSM
F.LOCN (T1,SYM);
GLOAD;
;..GO BACK TO REVERSE THE LEXEMES;
GOTO LSETU3
ENDD
FI
LSETU2:
;..PUT THE VALUE OF LOP IN AN AC;
IF LOP IS A POINTER
T.PTR (LOP);
THEN;..USE SAME ACC FOR VALUE AS FOR POINTER;
F.LOCN (T1,LOP);
ELSE;..USE NEXT FREE ACC;
MOVEI T1,ANYAC
FI
IF OP = "DIV" OR "REM"
MOVE T,OP
CAMN T,ZDIV
GOTO TRUE
CAME T,ZREM
GOTO FALSE
THEN;..GIVE LOP SPECIAL TYPE SO LOAD WILL USE 2 AC'S;
TLZ LOP,$TYPE
TLO LOP,$IDI
FI
;..LOAD THE VALUE, LEAVING THE PORTION OPEN;
MOVE T,OPMVLP
GLOAD;
ENDD
FI
ENDD;
FI
ENDD ; SETUP
SUBTTL CODE GENERATION ROUTINES * STOCON *
PROCEDURE STOCON
;..FIX UP LEXEME AND CONSTANT TABLE (IF NECESSARY)
; FOR A NEWLY GENERATED ONE WORD CONSTANT;
; ON ENTRY, VALUE OF CONSTANT IS IN T3;
; PARTIAL LEXEME FOR CONSTANT IS IN SYM;
; IF CONSTANT CAN BE IMMEDIATE, IT WILL BE STORED IN THE LEXEME;
; IF NOT IT WILL BE PUT INTO THE CONSTANT TABLE;
; COMPLETED LEXEME WILL BE PUT INTO SYM;
BEGIN
IF LEFT HALF OF CONSTANT = 0 AND SYM<TYPE> NEQ REAL
TLNN T3,777777
TN.R (SYM);
THEN;..WE HAVE A BOOLEAN OR INTEGER IMMEDIATE CONSTANT;
;LEX(SYM) _ (IMMED,SAME,SIMPLE,RH(T3));
TLZ SYM,$STATUS!$AM
TLO SYM,$SIM!$IMM
HRR SYM,T3
ELSE;..IT MAY BE REAL IMMEDIATE;
IF RIGHT HALF OF CONSTANT = 0 AND SYM<TYPE> = REAL
TRNN T3,777777
T.R (SYM);
THEN;..WE HAVE A REAL IMMEDIATE CONSTANT;
;LEX(SYM) _ (IMMED,SAME,SIMPLE,LH(T3));
TLZ SYM,$STATUS!$AM
TLO SYM,$SIM!$IMM
HLR SYM,T3
ELSE;..CONSTANT CANNOT BE IMMEDIATE;
;..PUT CONSTANT IN TABLE;
TOCT(1,SYM);
FI
FI
ENDD ; STOCON
ENDD; END OF MODULE MFUN
LIT
END