Trailing-Edge
-
PDP-10 Archives
-
ap-5069b-sb
-
10,6/algfun.mac
There are 8 other files named algfun.mac in the archive. Click here to see a list.
;
;
;
;
;
;
; COPYRIGHT (C) 1975,1976,1977
; DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
;
;
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE FOR USE ONLY ON A
; SINGLE COMPUTER SYSTEM AND MAY BE COPIED ONLY 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 EXCEPT FOR USE ON SUCH SYSTEM AND TO ONE WHO
; AGREES TO THESE LICENSE TERMS. TITLE TO AND OWNERSHIP OF THE
; SOFTWARE SHALL AT ALL TIMES REMAIN IN DEC.
;
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT
; NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL
; EQUIPMENT CORPORATION.
;
; DEC ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
; SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DEC.
;
;SUBTTL CODE GENERATION ROUTINES PART 2
; COPYRIGHT 1971,1972,1973,1974 DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
; 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 CTIR,CTILR,CTRI,CTRLR,CTLRI,CTLRR
INTERN LFADC,LFSBC,LFMPC,LFDVC
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
EXTERN SRCEMC,TARGMC ; SOURCE/TARGET FLAGS
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
CTIR: SKIPN SRCEMC ; IS IT A KI10 ?
JRST CTIR1 ; NO
FLTR A0,A0
POPJ SP,
CTIR1: ; THIS WAY ON A KA
IDIVI A0,400000 ; SEPARATE HIGH AND LOW HALVES
JUMPE A0,.+2 ; ONLY 18 BITS?
TLC A0,254000 ; NO -- SET UP HIGH HALF EXPONENT
TLC A1,233000 ; SET UP LOW HALF EXPONENT
FADR A0,A1 ; AND ADD BITS TOGETHER
POPJ SP,
CTILR: IDIVI A0,400000 ; SEPARATE HIGH AND LOW HALVES
JUMPE A0,.+2 ; ONLY 18 BITS?
TLC A0,254000 ; NO -- SET UP HIGH HALF EXPONENT
TLC A1,233000 ; SET UP LOW HALF EXPONENT
FADL A0,A1 ; AND ADD BITS TOGETHER
SKIPN TARGMC ; IF TARGET IS A KA, FINISH
POPJ SP,
TLZ A1,777000 ; IF KI10 TARGET, WIPE OUT LOW WORD EXPONENT
LSH A1,10 ; AND SHIFT UP FRACTION
POPJ SP,
CTRI: FADRI A0,(0.5) ; CTRI -- ADD 0.5
MULI A0,000400 ; SEPARATE EXPONENT AND MANTISSA
EXCH A0,A1
TSC A1,A1 ; FIX UP EXPONENT
ASH A0,-243(A1) ; AND SHIFT MANTISSA TO FORM INTEGER
POPJ SP,
EDIT (535) ; BAD COMPILER LR TO R IN V4 ONLY
CTRLR: MOVEI A1,0 ; [535] ZERO LOW ORDER WORD
POPJ SP,
CTLRI: SELMCC(CTLRI1,CTLRI2,CTLRI3) ; DECIDE THE MIX
DFAD A0,[
EXP 0.5,0.0]
GOTO CTLRI4
CTLRI1: MOVE A2,A1 ; STRICTLY KA
FADL A0,[0.5]
UFA A1,A2
FADL A0,A2
GOTO CTLRI4
CTLRI2: DMOVE A3,[
EXP 0.5,0.0]
PUSHJ SP,LRADAI
CTLRI4: 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
SKIPN TARGMC ; ONLY SHIFT FOR A KA TARGET
LSH A1,10 ; IT'S FOR KA10,SO SHIFT UP LOW ORDER FRACTION
SUBI A2,243 ; [E535]ADJUST EXPONENT
JUMPG A2,.+3 ; [E535]TOO BIG - OVERFLOW
EDIT(642); CORRECT SHIFT
ASHC A0,10(A2) ; [E642] SHIFT MANTISSA TO INTEGER
POPJ SP,
FAIL(128,SOFT,SYM,INTEGER TOO LARGE)
EDIT (535) ; DEAL WITH CONSTANT PROBLEMS
JUMPL A0,CTLRI5 ; [E535]NEG ?
HRLOI A0,377777 ; [E535]SET LARGEST POSITIVE NUMBER
POPJ SP,
CTLRI5: MOVSI A0,(400000,,0) ; [E535]LARGEST NEGATIVE
POPJ SP,
CTLRR: SELMCC(CTLRR1,CTLRR2,CTLRR3) ; LONG REAL TO REAL
; KI TARGET AND SOURCE
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 ; [E535]EXIT IF POSITIVE
MOVN A0,A0 ; OTHERWISE NEGATE
POPJ SP,
CTLRR1: ; KA TARGET
JUMPL A0,.+3 ; NEGATIVE NUMBER?
FADR A0,A1 ; NO -- ADD HIGH AND LOW WORDS TOGETHER
POPJ SP,
DFN A0,A1 ; YES -- NEGATE
FADR A0,A1 ; AND ADD HIGH AND LOW WORDS TOGETHER
MOVN A0,A0 ; NEGATE RESULT
POPJ SP,
CTLRR2: ; KI TARGET - KA PROCESSOR
JUMPGE A0,CTLRRC ; ONLY A PROBLEM IF -VE
SETCM A0,A0
MOVNS A1
TLZ A1,(1B0)
JUMPN A1,CTLRRD
AOJA A1,CTLRRD
SUBTTL LONGREAL COMPILE-TIME ARITHMETIC
;
; THIS CODE SORTS OUT THE TARGET AND SOURCE PROCESSORS
; AND PERFORMS THE BASIC OPERATIONS OF + - * /
; ACCCORDINGLY.
;
LFADC: ; ADDITION
SELMCC(LRADAA,LRADAI,LRADII)
LRADII: DFAD A0,A3
POPJ SP,
LFSBC: ; SUBTRACTION
SELMCC(LRSBAA,LRSBAI,LRSBII)
LRSBII: DFSB A0,A3
POPJ SP,
LFMPC: ; MULTIPLICATION
SELMCC(LRMPAA,LRMPAI,LRSBII)
LRMPII: DFMP A0,A3
POPJ SP,
LFDVC: ; DIVISION
SELMCC(LRDVAA,LRDVAI,LRDVII)
LRDVII: DFDV A0,A3
POPJ SP,
SUBTTL LONG REAL ARITHMETIC SUBROUTINES
; ON ENTRY:
; THE LEFT HAND OPERAND IS IN A0,A1
; THE RIGHT HAND OPERAND IS IN (A3,A4)
; THE LINK IS ON THE STACK
; ON EXIT, THE RESULT IS IN A0,A1
LRADAA: UFA A1,A4 ; ADD LOW ORDER PARTS IN A2
FADL A0,A3 ; ADD HIGH ORDER PARTS IN A0,A1
LFAD1: UFA A1,A2 ; ADD LOW PART OF HIGH SUM TO A2
FADL A0,A2 ; ADD LOW SUM TO HIGH SUM
JFOVO LFERR ; ERROR IF UNDER- OR OVERFLOW
POPJ SP,0
LRSBAA: DFN A0,A1 ; NEGATE LEFT HAND OPERAND
PUSHJ SP,LFADC ; PERFORM A LONG ADD
DFN A0,A1 ; AND NEGATE RESULT
POPJ SP,0
LRMPAA: MOVE A2,A0 ; COPY HIGH WORD OF LEFT HAND OPERAND
FMPR A2,A4 ; FORM ONE CROSS PRODUCT IN A2
FMPR A1,A3 ; FORM OTHER CROSS PRODUCT IN A1
UFA A1,A2 ; ADD CROSS PRODUCTS IN A2
FMPL A0,A3 ; FORM HIGH ORDER PRODUCT IN A0,A1
JRST LFAD1 ; FINISH UP LONG ADD
LRDVAA: FDVL A0,A3 ; GET HIGH PART OF QUOTIENT
MOVN A2,A0 ; AND NEGATE IT
FMPR A2,A4 ; MULTIPLY BY LOW PART OF DIVISOR
UFA A1,A2 ; ADD REMAINDER
FDVR A2,A3 ; DIVIDE SUM BY HIGH PART OF DIVISOR
FADL A0,A2 ; ADD RESULT TO ORIGINAL QUOTIENT
JFOVO LFERR ; ERROR IF UNDER- OR OVERFLOW
POPJ SP,0
LFERR:
FAIL(75,FRIED,SYM,OVERFLOW IN LONG REAL OPERATION ON CONSTANTS);
POPJ SP,0 ; ERROR EXIT
SUBTTL LONG REAL KI10 ARITHMETIC SIMULATION FOR KA10
; THESE ROUTINES ADD OR SUBTRACT TWO DOUBLE PRECISION
; NUMBERS. EACH NUMBER IS COMPOSED OF 8 BITS OF EXPONENT
; IN THE HI ORDER WORD WITH THE REMAINING 27 HI ORDER BITS
; AND THE 33 FIRST ARITHMETIC BITS OF THE LO ORDER AS THE
; MANTISSA. THE LAST 2 LO ORDER BITS ARE UNUSED. THE
; ANSWER IS RETURNED IN AC 0-1 AND THE ARGUMENTS ARE IN
; A0-1 AND A3-4 RESPECTIVELY
LREXP1: POINT ^D9,A0,^D8 ; EXPONENT FOR ARG1
LREXP2: POINT ^D9,A3,^D8 ; EXPONENT FOR ARG2
SGNA0==1
SGNA3==2
BITNEG==1B18
BIT1==200000
BIT2==100000
BITCRY==1000
BITEST==3400
LRLOW0: 377777777777
DEFINE MAKNEG(A)<
SETCM A,A
MOVNS A+1
TDNN A+1,LRLOW0
AOS A
>
LRSBAI: MAKNEG(A3) ; ENTRY FOR SUBTRACT
LRADAI: JUMPE A3,.+4 ; ENTRY FOR ADD
JUMPN A0,GA ; NEITHER ARG IS ZERO, SO GO ADD
MOVE A0,A3 ; A0=0 MEANS ARG2 IS ANSWER
MOVE A0+1,A3+1 ; RETURN IT TO EITHER AC OR MEM
POPJ SP,
GA: PUSH SP,A7
LDB A2,LREXP1 ; ARG1 EXP AND SIGN
LDB A5,LREXP2 ; ARG2 EXP AND SIGN
SKIPG A0 ; MAKE EXPS +
ANDCAI A2,777 ; ...
SKIPG A3 ; ...
ANDCAI A5,777 ; ...
MOVE A6,A5 ; GET EXP DIFFERENCE
SUB A6,A2 ; ...
SKIPLE A6 ; SAVE HIGHER EXP
AOS A2,A5 ; SAVED IN A2
TLZ A7,SGNA0+SGNA3 ; MARK SIGNS BEFORE SHIFT
JUMPGE A0,A0PL ; SKIP HAIR IF A0 +
TLO A7,SGNA0 ; MARK SIGN = -
MAKNEG A0
A0PL: JUMPGE A3,A3PL ; SKIP HAIR IF A3 = +
TLO A7,SGNA3 ; MARK SIGN = -
MAKNEG A3
A3PL: TLZ A0,777000 ; REMOVE EXPS
TLZ A3,777000 ; ...
JUMPLE A6,SHFT2 ; SHIFT ARG2
MOVNS A6 ; SHIFT ARG1 RIGHT
ASHC A0,(A6) ; UNNORMALIZE ARG1
CADD: TLNN A7,SGNA0 ; WAS A0 =-?
JRST A0WPL ; NO, SKIP RECOMPL
TLNE A7,SGNA3 ; IF BOTH WERE NEG,...
JRST BOTHN ; DON'T RECOMPL EITHER
MAKNEG A0
A0WPL: TLNN A7,SGNA3 ; WAS A3=-?
JRST A3WPL ; NO, SKIP RECOMPL
MAKNEG A3
A3WPL: TLZ A0,477000 ; SET TESTABLE BITS
TLZ A3,477000 ; TURN OTHERS OFF
JCRY1 .+1 ; TURN OFF OVFLO FLAG
ADD A0+1,A3+1 ; LO ORDER ADD
JCRY1 [
AOJA A0,TADD] ; ADD IN HI ORDER CARRY
TADD: ADD A0,A3 ; HI ORDER ADD
TLNE A0,BIT2 ; IS CARRY BIT TRUE
TLC A0,BITCRY ; NO, COMPL. IT
TLZN A0,BIT1 ; IS SUM -
JRST NORMA ; NO ON FIRST GLANCE
TLZE A0,BIT2 ; ...
TLNE A0,BITCRY ; ...
PUSHJ SP,NEG1 ; SUM=-,GO MAKE IT +
NORMA: TRO A2,200000 ; PROTECT AGAINST BORROWS FROM BITNEG
TLNN A0,1000 ; SKIP UNNORM IF NOT NEEDED
SOSA A2 ; BUT TELL THE EXPONENT ABOUT IT
ASHC A0,-1 ; THERE WAS SOMETHING THERE
D.MORM: TRO A2,200000 ; PROTECT AGAINST BORROWS FROM BITNEG
TLZ A0,777000 ; NO STRAY BITS
JUMPN A0,LOOPA+1 ; CHECK FOR ZERO
TDNN A0+1,LRLOW0 ; ...
JRST 2,@[
XWD 0,RET0] ; RETURN ZERO ANSWER
SKIPA ; ENTER NORMALIZE ROUTINE
LOOPA: ASHC A0,1 ; 1 BIT NORMALIZE
TLNN A0,400 ; IS NORMALIZE DONE?
SOJA A2,LOOPA ; IF NOT, SUB1 FROM EXP
TRNE A2,BITEST ; DID FP OV/UNDER FLO OCCUR?
JRST [
TRNN A2,040000 ; UNDERFLOW?
JRST OVTM2 ; NO, OVERFLOW
JRST UFLOW] ; YES
TRZE A2,BITNEG ; SHOULD ANS BE -
PUSHJ SP,NEG2 ; GO MAKE IT SO
DPB A2,LREXP1 ; STORE EXP AND SIGN
OVTM1: JRST 2,@[OVTA] ; CLEAR AR FLAGS
OVTM2: TRZ A2,400
TRZE A2,BITNEG ; SHOULD ANS BE -
PUSHJ SP,NEG2 ; GO MAKE IT SO
DPB A2,LREXP1 ; STORE EXPONENT AND SIGN
JRST 2,@[XWD 440200,OVTA]
RET0: SETZB A0,A0+1 ; RETURN ANS=0
OVTA: TLZ A0+1,400000 ; SET LOW SIGN +VE
LRKAEX: POP SP,A7
POPJ SP,
UFLOW: TRZ A2,400
TRZE A2,BITNEG
PUSHJ SP,NEG2
DPB A2,LREXP1
JRST 2,@[XWD 440300,OVTA]
SHFT2: ASHC A3,0(A6) ; UNNORMALIZE ARG2
AOJA A2,CADD ; INDICATE UNNORMALIZATION
NEG2: ANDCAI A2,777 ; MAKE EXP -
NEG1: TRO A2,BITNEG ; SET MARKER FOR -
MOVNS A0+1 ; TWOS COMPL
SETCMM A0 ; ...
TDNN A0+1,LRLOW0 ; ...
AOS A0 ; ...
JRST LRKAEX ; RESTORE A7 & RETURN
BOTHN: TRO A3,BITNEG ; SINCE BOTH WERE NEG, ANS ...
JRST A3WPL ; MUST BE NEG
; BASED ON THE FORTRAN ROUTINES IN DPSIM.MAC
; THESE ROUTINES MULTIPLY TWO DOUBLE PRECISION FLOATING
; NUMBERS.THE ARGUMENTS ARE IN A0-1 AND A3-4.
LRMPAI: PUSH SP,A7
JUMPE A3,RET0 ; ZERO PRODUCT
JUMPL A3,NEG2A ; IF -, PICK UP COMPL
NEG2RT: MOVE A7,A0 ; GET ARG1
JUMPE A0,RET0 ; ZERO PRODUCT
XOR A7,A0 ; GET ANSWER SIGN
JUMPL A0,NEG1A ; IF -, PICK UP ARG1 COMPL
NEG1RT: LDB A2,LREXP1 ; GET EXPS
LDB A5,LREXP2 ; ...
ADDI A2,-200(A5) ; GET PREDICTED EXP (EXCESS 200)
ANDI A2,077777 ; MASK EXPONENT TO 15 BITS
TLNE A7,400000 ; IF RESULT SHOULD BE NEG, ...
TRO A2,BITNEG ; SET INDICATOR
HRL A7,A2 ; SALT AWAY PROPOSED EXP
TLZ A0,777000 ; REMOVE EXPS
TLZ A3,777000 ; ...
ASHC A0,5 ; MAKE SEMI-PRODUCTS MORE SIGNIFICANT
ASHC A3,5 ; ...
MUL A0+1,A3 ; FORM LO ORDER SEMI-PRODS
MUL A3+1,A0 ; ...
MOVE A5,A0+1 ; PROTECT FROM CREEPING SIGNIFICANCE
MUL A0,A3 ; HI ORDER SEMI-PROD
JCRY1 .+1 ; CLEAR FLAG
ADD A0+1,A5 ; FIRST LO SEMI-PROD
JCRY1 [AOJA A0,A1RT] ; ADD IN CARRY
A1RT: ADD A0+1,A3+1 ; SECOND LO SEMI-PROD
JCRY1 [AOJA A0,A3RT] ; ADD IN CARRY
A3RT: TRNE A0+1,2 ; PATCH FOR MORE PRECISION
ADDI A0+1,2
ASHC A0,-2
HLRZ A2,A7 ; RECLAIM EXP
JRST D.MORM ; GO NORMALIZE AND RETURN
NEG2A: SETCM A3,A3 ; TW0S COMPL ARG2
MOVNS A3+1 ; ...
TDNN A3+1,LRLOW0 ; ...
AOJA A3,NEG2RT ; ...
JRST NEG2RT ; ...
NEG1A: SETCM A0,A0 ; TWOS COMPL ARG2
MOVNS A0+1 ; ...
TDNN A0+1,LRLOW0 ; ...
AOJA A0,NEG1RT ; ...
JRST NEG1RT ; ...
; THESE ROUTINES FORM THE QUOTIENT OF TWO DOUBLE
; PRECISION FLOATING POINT NUMBERS. THE DIVIDEND
; IS IN A0-1 THE DIVISOR IS IN A3-4. THE QUOTIENT IS RETURNED
; IN A0-1.
LRDVAI: PUSH SP,A7
JUMPL A3,NEG2B ; IF -, PICK UP COMPL
NEG2RB: MOVE A7,A0 ; GET AT DIVIDEND
XOR A7,A0 ; SIGN OF A7= SIGN OF QUOTIENT
JUMPL A0,NEG1B ; IF A0=-, PICK UP COMPL
NEG1RB: TDNE A0,[777777777] ; IS DIVIDEND ZERO?
JRST RET0
TDNN A3,[777777777] ; OR HAS 11TH COMMANDMENT BEEN VIOLATED?
JRST 2,@[XWD 440240,RET0] ; SET DIVIDE CHECK, RETURN 0
LDB A2,LREXP1 ; GET EXPS
LDB A5,LREXP2 ; ...
SUBI A2,-201(A5) ; GET EXP DIFFERENCE
ANDI A2,077777 ; MASK RESULTANT EXP TO 15 BITS
TLNE A7,400000 ; MARK QUOTIENT SIGN
TRO A2,BITNEG ; ...
HRL A7,A2 ; SAVE PROPOSED EXP
TLZ A0,777000 ; GRONK EXPS
ASHC A3,8 ; AND MAKE QUOTIENT TO RIGHT PLACE
ARITH: DIV A0,A3 ; FIRST DIVISION
MUL A3+1,A0 ; FORM Q1*D
SETCA A3+1, ; TWO'S COMPL OF Q1*D
TDNN A3+2,LRLOW0 ; ...
AOS A3+1 ; ...
ADD A0+1,A3+1 ; A0+1 CONTAINS A0+1-Q1*D
DIV A0+1,A3 ; SECOND DIVISION
HLRZ A3,A7 ; GET EXP
JUMPGE A0+1,D.MORM ; GO NORMALIZE IF POSITIVE
SOJA A0,D.MORM ; ADJUST BEFORE NORMALIZE IF NEGATIVE
NEG2B: SETCM A3,A5 ; TWOS COMPL OF DIVISOR
MOVNS A3+1 ; ...
TDNN A3+1,LRLOW0 ; ...
AOJA A3,NEG2RB ; ...
JRST NEG2RB ; ...
NEG1B: SETCM A0,A0 ; TWOS COMPL OF DIVIDEND
MOVNS A0+1 ; ...
TDNN A0+1,LRLOW0 ; ...
AOJA A0,NEG1RB ; ...
JRST NEG1RB ; ...
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: PUSHJ SP,CTIR ; 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
SELMCC(POWL2,POWL3,POWL1)
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
; KA TARGET ON KA SOURCE M/C
POWL2: TRZE A7,000001 ; BIT SET IN EXPONENT?
XCT [
PUSHJ SP,LRDVAA
PUSHJ SP,LRMPAA](A6)
JUMPE A7,POWLEX ; EXIT IF FINISHED
MOVE A5,A3 ; OTHERWISE SQUARE THE MULTIPLIER
FMPR A5,A4 ; LONG REAL MULTIPLY
FMPR A4,A3 ; (A3,A4) * (A3,A4)
UFA A4,A5
FMPL A3,A3
UFA A4,A5
FADL A3,A5
LSH A7,-1 ; SHIFT BIT OUT OF EXPONENT
JRST POWL2 ; AND CARRY ON
; KI SIMULATION ON KA M/C
POWL3: TRZE A7,1 ; BIT SET IN EXPONENT ?
XCT [
PUSHJ SP,LRDVAI
PUSHJ SP,LRMPAI](A6) ; YES - DO MULTIPLY/DIVIDE
JUMPE A7,POWLEX ; FINISHED ?
PUSH SP,A0 ; SAVE A0 & A1, BECAUSE
PUSH SP,A1 ; SIMULATION ROUTINES USE THEM
MOVE A0,A3
MOVE A0+1,A3+1
PUSHJ SP,LRMPAI ; SQUARE THE EXPONENT - ANS IN A0,A1
MOVE A3,A0
MOVE A3+1,A0+1 ; GET IT TO RIGHT PLACE
POP SP,A0+1
POP SP,A0
LSH A7,-1 ; SHIFT BIT OUT OF EXPONENT
JRST POWL3
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 ; [E700]
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(700); Dont force constants to D.P. unnecessarily
;.SYM IS LONG REAL - CHECK IF GENUINE ; [E700]
IF SYM = PSEUDO-LONG CONSTANT ; [E700]
TLNN SYM,$TYPE-$LR ; [E700]
T.CONST (SYM) ; [E700]
TLNE SYM,$CT-$IMM ; [E700]
TLNN SYM,$DEC ; [E700]
GOTO FALSE ; [E700]
F.LOCN (T2,SYM) ; [E700]
ADD T2,CONTAB ; [E700]
SKIPL T4,3(T2) ; [E700]
GOTO FALSE ; [E700]
THEN;.MAKE IT A GENUINE LONG REAL CONSTANT; [E700]
MOVE T3,2(T2) ; [E700]
TLZ T4,(1B0) ; [E700]
TOCT (2,SYM) ; [E700]
FI; ; [E700]
ENDD; ; [E700]
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(700); Dont force constants to D.P. unnecessarily
BEGIN; ; [E700]
IF SYM = PSEUDO-LONG REAL CONSTANT ; [E700]
TLNN SYM,$TYPE-$LR ; [E700]
T.CONST (SYM) ; [E700]
TLNE SYM,$CT-$IMM ; [E700]
TLNN SYM,$DEC ; [E700]
GOTO FALSE ; [E700]
F.LOCN (T2,SYM) ; [E700]
ADD T2,CONTAB ; [E700]
SKIPL T4,3(T2) ; [E700]
GOTO FALSE ; [E700]
THEN;..CONVERT IT TO A REAL ; [E700]
MOVE T3,A0 ; [E700]
MOVE A0,2(T2) ; [E700]
MOVE A1,3(T2) ; [E700]
TLZ A1,(1B0) ; [E700]
PUSHJ SP,CTLRR ; [E700]
EXCH T3,A0 ; [E700]
TLZ SYM,$TYPE
TLO SYM,$R
STOCON; ; [E700]
HRRZ T,LOP ; [E700]
FI; ; [E700]
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(665); 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
EDIT (537) ; FORMAL STRINGS WITH FORMAL SUBSCRIPTS (S10-10644)
REVER;[E537]
MERGEPORTIONS;
COMBLEX;[E537]
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;$
JUMPE T,FALSE;$
; 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(702); Do the correct thing for a zero increment
IF CONSTANT GEQ 0
JUMPL T3,FALSE ; [E702]
THEN;..CONSTANT >= 0. NORMAL TEST ; [E702]
MOVE T,ZLEQ;$
ELSE;..CONSTANT < 0. REVERSE THE TEST ; [E702]
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
EDIT (602) ; PREVENT OVERFLOWS IN FOR-LOOP TEST (USED TO DO MUL)
;.. 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(702); Don't generate an "ADDB" for a zero increment !
IF SYM IS A CONSTANT WITH VALUE ZERO ; [E702]
T.CONST (SYM) ; [E702]
F.LOCN (T,SYM) ; [E702]
TLNN SYM,$AM-$IMM ; [E702]
JRST .+3 ; [E702]
ADD T,CONTAB ; [E702]
MOVE T,1(T) ; [E702]
JUMPN T,FALSE ; [E702]
THEN;..NO NEED TO GENERATE AN ADDB ; [E702]
MOVE T4,OPMOVE ; [E702]
GOTO LCGIN0 ; [E702]
FI; ; [E702]
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: ; [E702] 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
; [E702] UNLESS OPCODE = MOVE, WHEN AC0 IS O.K.
TLNE T4,174000 ; [E702]
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 ; [E700]
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 ; [E700]
EXCH SYM,LOP;$
MOVNI REV,SYM+LOP(REV);$
FI;
ENDD;
FI;
EDIT(700);Don't force constants to D.P. unnecessarily
; TYPES MATCH - CHECK FOR PSEUDO-LONG REAL ; [E700]
IF TYPE = LONG REAL ; [E700]
T.LR (SYM) ; [E700]
THEN; ; [E700]
BEGIN; ; [E700]
IF SYM = PSEUDO-LONG REAL CONSTANT & LOP # CONSTANT
TLNE LOP,$CONST ; [E700]
T.CONST (SYM) ; [E700]
TLNE SYM,$CT-$IMM ; [E700]
TLNN SYM,$DEC ; [E700]
GOTO FALSE ; [E700]
F.LOCN (T2,SYM) ; [E700]
ADD T2,CONTAB ; [E700]
SKIPL T4,3(T2) ; [E700]
GOTO FALSE ; [E700]
THEN;..CONVERT SYM TO A GENUINE LONG REAL CONSTANT
MOVE T3,2(T2) ; [E700]
TLZ T4,(1B0) ; [E700]
TOCT (2,SYM) ; [E700]
ELSE; ; [E700]
BEGIN; ; [E700]
IF LOP = PSEUDO-LONG REAL CONSTANT & SYM # CONSTANT
TLNE SYM,$CONST ; [E700]
T.CONST (LOP) ; [E700]
TLNE LOP,$CT-$IMM ; [E700]
TLNN LOP,$DEC ; [E700]
GOTO FALSE ; [E700]
F.LOCN (T2,LOP) ; [E700]
ADD T2,CONTAB ; [E700]
SKIPL T4,3(T2) ; [E700]
GOTO FALSE ; [E700]
THEN;..CONVERT LOP TO A GENUINE LONG REAL CONSTANT
MOVE T3,2(T2) ; [E700]
TLZ T4,(1B0) ; [E700]
TOCT (2,LOP) ; [E700]
FI; ; [E700]
ENDD; ; [E700]
FI; ; [E700]
ENDD; ; [E700]
FI; ; [E700]
;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(700) ;New routine to match type of SYM to LOP
BEGIN; ; [E700]
IF LOP = PSEUDO-LONG CONSTANT & SYM # CONSTANT ; [E700]
TLNN LOP,<$TYPE-$LR>!$CONST;
TLNN SYM,$CONST ; [E700]
GOTO FALSE ; [E700]
TLNE LOP,$CT-$IMM ; [E700]
TLNN LOP,$DEC ; [E700]
GOTO FALSE ; [E700]
F.LOCN (T2,LOP) ; [E700]
ADD T2,CONTAB ; [E700]
SKIPL A1,3(T2) ; [E700]
GOTO FALSE ; [E700]
THEN; FIRST WE MUST TRUNCATE LOP TO A REAL ; [E700]
MOVE T3,A0 ; [E700]
MOVE A0,2(T2) ; [E700]
TLZ A1,(1B0) ; [E700]
PUSHJ SP,CTLRR ; [E700]
EXCH T3,A0 ; [E700]
TLZ LOP,$TYPE ; [E700]
TLO LOP,$R ; [E700]
EXCH LOP,SYM ; [E700]
PUSHJ SP,.STOCON ; [E700]
EXCH LOP,SYM ; [E700]
; IF SYM<TYPE> # REAL, SKIP INTO THE "ELSE" CLAUSE ; [E700]
TLNN SYM,$TYPE-$R ; [E700]
ELSE; WE NEED TO CONVERT SYM TO THE TYPE OF LOP ; [E700]
HLRZ T,LOP ; [E700]
ANDI T,$TYPE ; [E700]
PUSHJ SP,.CONVERT ; [E700]
FI; ; [E700]
POPJ SP, ; [E700]
ENDD; TCHECK ; [E700]
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;
MOVE A0,2(T2);$
MOVE A1,3(T2);$
TLZ A1,(1B0) ; [E700]
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) ; [E700]
;..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