Google
 

Trailing-Edge - PDP-10 Archives - decuslib10-02 - 43,50263/sddsys.vms
There are 2 other files named sddsys.vms in the archive. Click here to see a list.
	TITLE	S$$SYS  SYSTEM BASIC MODULE
	SUBTTL	DESCRIPTION OF FUNCTIONS
	SALL
	RADIX	10
	SEARCH	S$$NDF

	COMMENT"
	THIS MODULE CONTAINS ALL THE BASIC FUNCTIONS OF THE RUN-TIME
SYSTEM, DESCRIBED BRIEFLY BELOW AND FUNCTIONALLY IN THE APPROPRIATE
SECTION.

SYSTEM INITIALIZATION- INITIALIZES SYSTEM PARAMETERS, STACKS, AND INITIAL-
LIZES THE MAIN PROGRAM. SYSTEM COMMON IS DEFINED TO RECLAIM AS MUCH OF
THE CORE USED BY THE INITIALIZATION AS POSSIBLE.

PROGRAM INITIALIZATION- INCORPORATES THE NEW PROGRAM'S PARAMETERS AND
SYMBOLS INTO THE SYSTEM.

UUO HANDLER- DISPATCHES OPERATIONS 01-37.

INTERRUPT HANDLER- DISPATCHES PROGRAM-TRAPPED INTERRUPTS

STACK OVERFLOW- EXPANDS STACKS WHEN THEY OVERFLOW.

FREE STORAGE- DYNAMIC STORAGE ALLOCATION FUNCTIONS.

INPUT/OUTPUT- ELEMENTARY I/O FUNCTIONS.

RUN-TIME ERRORS- HANDLES CONDITIONALLY OR UNCONDITIONALLY FATAL ERRORS.

SYSTEM EXITS- NORMAL OR ERROR EXITS FROM SYSTEM.

RUN-TIME SYMBOL TABLE- BASIC AND SYSTEM SYMBOL LOOKUP FUNCTIONS
AND SYMBOL BLOCK INITIALIZATION ROUTINE.

FUNCTION CALL HANDLER- DISPATCHES PRIMITIVE AND PROGRAMMER-DEFINED FUNC-
TION CALLS, FIELD AND DATATYPE REFERENCES.

DEDICATED MODE ROUTINES- DISPATCHES DEDICATED ASSIGNMENTS AND DEDICATED
STRING CONCATENATION.

DESCRIPTOR MODE CONVERSION- CONVERTS FROM DESCRIPTOR MODE INTO
INTEGER OR REAL.

ARRAY/TABLE REFERENCE HANDLER- PRODUCES VALUE OR NAME OF ARRAY OR
TABLE ELEMENT.

FAILPOINT ROUTINE- HANDLES GLOBAL, NEGATION, AND UNEVALUATED EXPRESSION
FAILURES.

UTILITY ROUTINES- ASSORTED CONVERSION ROUTINES.

DUMMY FORTRAN ENTRIES- USED TO SATISFY FORTRAN MATH LIBRARY ROUTINES."
	SUBTTL	SYSTEM INITIALIZATION

	ENTRY	S$$ILZ
	EXTERN	.JBUUO,.JB41,.JBREL,.JBSA,.JBFF,.JBAPR,.JBCNI
	EXTERN	.JBTPC,.JBCOR

	COMMENT/ SYSTEM INITIALIZATION
CALL:	JSP	R12,S$$ILZ	; OCCURS AT THE START OF MAIN PROGRAM
	XWD	HSHSIZ,MAINPB	; WHERE HSHSIZ IS THE BUCKET TABLE SIZE,
DEFAULT (P$HSHS) USED IF 0, AND MAINPB IS THE MAIN PROGRAM PARAMETER
BLOCK POINTER.

	DOES A RESET, SETS UP UUO AND INTERRUPT SERVICE, SAVES START
TIME, INITIALIZES FREE STORAGE, STACKS, CHANNEL TABLE, BUCKET TABLE, AND
SYSTEM SYMBOLS, AND INITIALIZES MAIN PROGRAM.
	THE CORE OCCUPIED BY THE INITIALIZATION CODE IS RECLAIMED FOR
USE BY VARIABLES AND TABLES IN THIS MODULE THAT DO NOT REQUIRE INITIAL
VALUES/

S$$ILZ:	RESET		; RESET SYSTEM
	SETZ	R0,	; GET START TIME OF EXECUTION
	RUNTIM	R0,	; FOR THIS JOB
	MOVEM	R0,SSTT	; SAVE
	JSR	S$$PFZ##	; INITIALIZE PAGE FAULT HANDLER
	MOVE	R0,S$$UUL	; SET UP UUO HANDLER
	MOVEM	R0,.JB41
	MOVEI	R0,INTRUP	; SET UP INTERRUPT HANDLER
	MOVEM	R0,.JBAPR
	MOVEI	R0,^O620110	; REPETITIVE ENABLE PUSHDOWN OVFLOW,
	APRENB	R0,	; MEMORY, ARITH OVFLOW, DIVIDE CHECK

; INITIALIZE FREE STORAGE
	HLRZ	R2,.JBSA	; GET FIRST FREE LOCATION
	MOVEM	R2,MINCOR	; SAVE
	MOVEM	R2,CURCOR
	ADDI	R2,P$GBUF+P$SSSZ+P$ESSZ+P$PSSZ+P$ASSZ+P$CSSZ
			; ADD CORE NEEDED BY GARBAGE AND OTHER STACKS
	HLRZ	R1,(R12)	; GET BUCKET TABLE SIZE
	JUMPG	R1,.+2	; SKIP IF SPECIFIED AND > 0
	MOVEI	R1,P$HSHS	; USE DEFAULT SIZE
	HRRM	R1,DOHASH	; SAVE IN HASHING OPERATION
	ADDI	R2,1(R1)	; ADD CORE NEEDED BY BUCKET TABLE
	CAMG	R2,.JBREL	; NEED TO EXPAND CORE?
	JRST	.+3	; NO
	JSP	R6,EXPCOR	; YES, TRY
	UFERR	4,R12	; CAN'T MAKE IT, ERROR
	MOVE	R0,.JBREL	; GET HIGHEST ADDRESS FOR USER
	MOVEM	R0,MAXCOR	; SAVE
	SUBI	R0,P$GBUF	; HIGHEST ADDRESS FOR FREE STORAGE
	MOVEM	R0,MAXFRE	; SAVE
	MOVEM	R0,.JBFF	; USE GARB STACK AREA FOR DUMMY BUFFERS
	HRLM	R0,.JBSA	; UPDATE JOB PARAMETERS
	HRLM	R0,.JBCOR
; INITIALIZE STACKS
	MOVNI	R7,4	; SET UP FOR FIVE STACKS
ILZSTK:	MOVE	R8,CSBA(R7)	; GET EXTENSION, INITIAL SIZE
	MOVEI	R0,(R8)	; INITIAL SIZE FOR STACK
	JSP	R6,S$$GNS	; GET NONRETURNABLE BLOCK
	MOVNI	R2,(R8)	; GET -(SIZE-2) INTO HU
	HRLI	R1,2(R2)
	MOVEM	R1,CSBA(R7)	; SAVE POINTER IN STACK BASE WORD
	HLRM	R8,(R1)	; SAVE STACK EXTENSION SIZE
	HRLI	R0,CSBA(R7)	; FORM REVERSE OF LAST STACK BLOCK WORD
	ADDI	R8,-1(R1)	; GET POINTER TO LAST WORD
	MOVSM	R0,(R8)	; STORE SIZE, PTR TO BASE WORD
	AOJLE	R7,ILZSTK	; LOOP FOR EACH STACK
	MOVE	SS,SSBA	; INITIALIZE SS
	MOVE	ES,ESBA	; INITIALIZE ES

; INITIALIZE CHANNEL TABLE
	SETZM	CHNTBL	; ZERO CHNTBL(0) - CHNTBL(15)
	MOVEI	R1,CHNTBL+1
	HRLI	R1,CHNTBL
	BLT	R1,CHNTBL+15

; INITIALIZE BUCKET TABLE
	HRRZ	R0,DOHASH	; GET BUCKET TABLE SIZE
	ADDI	R0,1	; +1 FOR BLOCK HEADER WORD
	JSP	R6,S$$GNS	; GET NONRETURNABLE BLOCK
	ADDI	R1,1	; POINTER TO FIRST BUCKET
	HRRM	R1,BUCKTB	; SAVE
	SETZM	(R1)	; ZERO ALL BUCKETS
	ADDI	R0,-2(R1)	; UP TO LAST
	HRLI	R1,1(R1)	; USING
	MOVS	R1,R1	; BLT WORD
	MOVE	R2,R0	; AND LAST LOC INDEX
	BLT	R1,(R2)

; INITIALIZE GLOBAL SYMBOLS
	MOVEI	R9,GLOBSY	; GET START OF GLOBAL SYMBOL BLOCK
	JSP	R10,S$$SYI	; DO INITIALIZATION

; INITIALIZE THE MAIN PROGRAM
	HRRZ	R10,(R12)	; GET PARAMETER BLOCK POINTER
	MOVEM	R10,PRGL	; SAVE IN PROGRAM LIST AS LAST
	HRLM	R10,PRGL	; AND FIRST PROGRAM
	MOVEI	R9,1(R10)	; SAVE PARBLK+1
	MOVEM	R9,PBLP	; AS CURRENT PROGRAM BLOCK
	JSP	R11,INIPR1	; INITIALIZE PROGRAM
	JRST	1(R12)	; RETURN
ILZEND:
; DEFINITIONS USED TO RECLAIM INITIALIZATION AREA
	SST=S$$ILZ	; SCRATCH AREA START
	SED=ILZEND	; SCRATCH AREA END
	DEFINE	VARDEF(N,S)	;;DEFINE SPACE FOR NAME N OF SIZE S
<	SST1=SST
	IFLE	SST+S-SED,	;;IF ENOUGH ROOM LEFT IN SCRATCH AREA
 <	N=SST			;;USE THE SCRATCH AREA
	SST1=SST+S>		;;AND INCREASE THE POINTER
	IFG	SST+S-SED,
 <N:	BLOCK	S>		;;OTHERWISE USE SPACE WHERE CALLED
	SST=SST1>

; WORD FORMAT DEFINITIONS
	DEFINE	SHD(T,S,P)	;;STORAGE BLOCK HEADER WORD
<	BYTE	(2)T(16)S(18)P>	;;TYPE, SIZE, POINTER

	DEFINE	SDC(S,C,N)	;;STRING DESCRIPTOR
<	POINT	7,[SHD	2,S,C	;;SIZE, CHARACTER COUNT
		ASCII/N/],35>	;;AND STRING

	DEFINE	NDC(D,P)	;;NAME DESCRIPTOR
<	BYTE	(4)4(2)D(12)0(18)P>	;;DEDICATION, POINTER

; DEFINE JFFO IF ASSEMBLY IS FOR PDP-6
	IFN	P$PDP6,
<	DEFINE	JFFO(REG,LOC)
<	JRST	[
	SETZ	REG'+1,
	JUMPE	REG,.+1
	EXCH	REG'+2,.
	MOVEM	REG,11(REG'+2)
	TLNE	REG,1B18
	JRST	8(REG'+2)
	LSH	REG,1
	AOJA	REG'+1,4(REG'+2)
	MOVE	REG,11(REG'+2)
	EXCH	REG'+2,.
	JRST	LOC
	0]>>
	SUBTTL	SYSTEM COMMON

	ENTRY	S$$FLP,S$$KWD,S$$CHT,S$$STB,S$$STS,S$$STP,S$$GLP
	ENTRY	S$$PGL,S$$LFC,S$$TMS,S$$PBP,S$$RTP,S$$NUL
	ENTRY	S$$INP,S$$INC,S$$OUT,S$$OUC,S$$TAC,S$$SJC,S$$SST,S$$PRL
	ENTRY	S$$TA1
	EXTERN	S$$SRT,S$$FRT,S$$NRT

	COMMENT/ SYSTEM COMMON
	DEFINES MOST VARIABLES, PARAMETERS, TABLES AND CONSTANTS
COMMONLY USED BY THE SYSTEM/

; ELEMENTS THAT MUST APPEAR FIRST IN THE SCRATCH AREA
	VARDEF	SSTT,1	; SYSTEM START TIME
	S$$SST=SSTT
	VARDEF	MINCOR,1	; LOW FREE CORE POINTER
	S$$LFC=MINCOR
	VARDEF	MAXCOR,1	; HIGH USER CORE POINTER
	VARDEF	MAXFRE,1	; HIGH FREE CORE POINTER
	VARDEF	CURCOR,1	; QUICKMODE CORE POINTER
	VARDEF	CHNTBL,16	; CHANNEL TABLE
	S$$CHT=CHNTBL

; STACK PARAMETERS
SSBA:	XWD	P$SSXT,P$SSSZ	; SS BASE WORD
ESBA:	XWD	P$ESXT,P$ESSZ	; ES BASE WORD
	S$$STB=ESBA
PSBA:	XWD	P$PSXT,P$PSSZ	; PS BASE WORD
ASBA:	XWD	P$ASXT,P$ASSZ	; AS BASE WORD
CSBA:	XWD	P$CSXT,P$CSSZ	; CS BASE WORD
	VARDEF	SSSA,1	; SS SAVED
	VARDEF	ESSA,1	; ES SAVED
	S$$STS=ESSA
	VARDEF	PSSA,1	; PS SAVED
	VARDEF	ASSA,1	; AS SAVED
	VARDEF	CSSA,1	; CS SAVED
SSPR:	XWD	0,0	; SS PREVIOUS
ESPR:	XWD	0,0	; ES PREVIOUS
	S$$STP=ESPR
PSPR:	XWD	0,0	; PS PREVIOUS
ASPR:	XWD	0,0	; AS PREVIOUS
CSPR:	XWD	0,0	; CS PREVIOUS

; GLOBAL PARAMETERS
	VARDEF	PRGL,1	; PROGRAM LIST
	S$$PRL=PRGL
S$$GLP:
GLST:	BYTE	(2)1,1(1)1(13)0(18)GLSTBB	; GLOBAL SYMBOL TBL DSCR
GLVL:	XWD	GLOBVR,GLOBVR	; VARIABLE BLOCK LIST
GLVX:	8		; NEXT GLOBAL VARIABLE INDEX
LTBL:	0		; LATEST TABLE NUMBER

; DYNAMIC PARAMETERS
	VARDEF	PRGLNK,1	; PROGRAM LINK
	S$$PGL=PRGLNK
	VARDEF	TIMR,1	; CURRENT STATEMENT START TIME
	S$$TMS=TIMR
	VARDEF	PBLP,1	; CURRENT PARAMETER BLOCK
	S$$PBP=PBLP
	VARDEF	FAIL,1	; FAILPOINT POINTER
	S$$FLP=FAIL
; SYSTEM VARIABLE STORAGE BLOCK (GLOBAL VARIABLES)
GLOBVR:	SHD	2,8,0	; 7 VARS
LOCINP:	0		; 'INPUT'
LOCINC:	0		; 'INPUTC'
LOCOUT:	0		; 'OUTPUT'
LOCOUC:	0		; 'OUTPUTC'
TMPA:	0		; TEMPORARY AC
	S$$TAC=TMPA
SUBJ:	0		; SUBJECT STRING FOR PATTERN MATCH
	S$$SJC=SUBJ
TMP1:	0		; TEMPORARY VALUE #1
	S$$TA1=TMP1

; SYSTEM SYMBOL BLOCK
GLOBSY:	SHD	2,33,-8	; HEADER WORD
	XWD	0,0	; 'INPUT' VARIABLE
	2B4
	SDC	2,5,INPUT
S$$INP:	NDC	0,-1
	XWD	0,0	; 'INPUTC' VARIABLE
	2B4
	SDC	3,6,INPUTC
S$$INC:	NDC	0,-2
	XWD	0,0	; 'OUTPUT' VARIABLE
	2B4
	SDC	3,6,OUTPUT
S$$OUT:	NDC	0,-3
	XWD	0,0	; 'OUTPUTC' VARIABLE
	2B4
	SDC	3,7,OUTPUTC
S$$OUC:	NDC	0,-4
	XWD	0,0	; 'RETURN' LABEL
	4B4
S$$RTP:	SDC	3,6,RETURN
	JRST	S$$SRT
	XWD	0,0	; 'FRETURN' LABEL
	4B4
	SDC	3,7,FRETURN
	JRST	S$$FRT
	XWD	0,0	; 'NRETURN' LABEL
	4B4
	SDC	3,7,NRETURN
	JRST	S$$NRT
	XWD	0,0	; 'END' LABEL
	4B4
	SDC	2,3,END
	JRST	S$$SXT

; GLOBAL SYMBOL TABLE BASE BLOCK
GLSTBB:	SHD	2,3,P$GSXT
	XWD	0,.+2
	XWD	0,0	; NO MORE ROOM LEFT, USE EXTENSION

; KEYWORDS
S$$KWD:
;	INITIAL		; NAME		TYPE	INDEX	PROTECTED?
STFC:	0		; &STFCOUNT	INT	0	YES
LSTN:	0		; &LASTNO	INT	1	YES
STNO:	0		; &STNO		INT	2	YES
FNCL:	0		; &FNCLEVEL	INT	3	YES
STCN:	0		; &STCOUNT	INT	4	YES
ERRT:	0		; &ERRTYPE	INT	5	YES
RTNT:	POINT 7,NULSTR,35 ;&RTNTYPE	STRING	6	YES
	POINT 7,ALPHAB,35 ;&ALPHABET	STRING	7	YES
ABND:	0		; &ABEND	INT	8	NO
ANCH:	0		; &ANCHOR	INT	9	NO
FULS:	0		; &FULLSCAN	INT	10	NO
STNT:	0		; &STNTRACE	INT	11	NO
MXLN:	P$MXLN		; &MAXLNGTH	INT	12	NO
STLT:	P$MXST		; &STLIMIT	INT	13	NO
ERLT:	0		; &ERRLIMIT	INT	14	NO
DENS:	P$DENS		; &DENSITY	INT	15	NO
KINP:	1		; &INPUT	INT	16	NO
KOUT:	1		; &OUTPUT	INT	17	NO
DUMP:	0		; &DUMP		INT	18	NO
SLFR:	0		; &SLOWFRAG	INT	19	NO

; SYSTEM CONSTANTS
NULSTR:	SHD	2,1,0	; NULL STRING
NULDSC:	POINT	7,NULSTR,35	; NULL DESCRIPTOR
	S$$NUL=NULDSC
	RPTC=0
ALPHAB:	SHD	2,27,128	; ALPHABET STRING
	REPEAT	25,<
	BYTE	(7)RPTC,RPTC+1,RPTC+2,RPTC+3,RPTC+4
	RPTC=RPTC+5>
	BYTE	(7)125,126,127
	SUBTTL	PROGRAM INITIALIZATION

	ENTRY	S$$IPR

	COMMENT/
CALL:	JSP	R11,S$$IPR	; WITH PARBLK PTR IN R10
	ADDS PROGRAM TO PROGRAM LIST, SETS INITIALIZATION FLAG, ADDS
VARIABLE STORAGE BLOCK, IF ANY, TO FRONT OF VARIABLE STORAGE BLOCK LIST
, CREATES TIMING BLOCK IF REQUIRED, AND INITIALIZES SYMBOLS, IF ANY/

S$$IPR:	MOVE	R9,PRGL	; GET FIRST,LAST PROGRAM POINTERS
	HRRM	R10,(R9)	; ADD CURRENT ONE TO END OF CHAIN
	HRRI	R9,(R10)	; NEW LAST PROG PTR
	MOVEM	R9,PRGL	; RESTORE
INIPR1:	HRLZI	R9,-1	; SET INITIALIZATION FLAG, END OF CHAIN
	EXCH	R9,(R10)	; AND FETCH VARIABLE STORAGE POINTER
	JUMPE	R9,INIPR2	; SKIP IF THERE IS NONE
	HLRZ	R8,GLVL	; FIRST BLOCK IN VAR BLOCK LIST
	HRRM	R8,(R9)	; IS NOW SECOND
	HRLM	R9,GLVL	; AND CURRENT IS FIRST
INIPR2:	HRRZ	R9,1(R10)	; GET NSTAT
	SETZ	R1,
	JUMPE	R9,INIPR3	; SKIP IF NO TIMING BLOCK NEEDED
	MOVEI	R0,1(R9)	; NUMBER OF WORDS NEEDED
	JSP	R6,S$$GNS	; GET NONRETURNABLE BLOCK
	HLLZS	(R1)	; CLEAR RH OF FIRST WORD (TOTTIM)
	HRLZI	R2,1(R1)	; BLT WORD
	HRRI	R2,2(R1)	; FOR REST OF BLOCK
	SETZM	1(R1)	; ZERO ALL WORDS
	ADDI	R9,(R1)	; UP TO END OF BLOCK
	BLT	R2,(R9)
INIPR3:	EXCH	R1,1(R10)	; SAVE TIMING BLOCK POINTER, IF
			; ANY, AND GET SYMBOL BLOCK POINTER
	TLNN	R1,^O777777	; ANY SYMBOLS?
	JRST	(R11)	; NO, RETURN
	AOS	R8,LTBL	; GET NEW TABLE NUMBER
	HRLM	R8,1(R10)	; SAVE IN PARAMETER BLOCK
	HRLZI	R8,(R8)	; PREPARE FOR SYMBOL INITIALIZATION
	HLRZ	R9,R1	; GET SYMBOL BLOCK POINTER
	JSP	R10,S$$SYI	; INITIALIZE SYMBOLS
	JRST	(R11)	; RETURN
	SUBTTL	UUO HANDLER

	ENTRY	S$$UUL,S$$UDU,S$$UPC

	COMMENT/
CALL:	UUO	AC,ADDR	; LEAVES PC IN S$$UPC AND UUO AC,EFFADR IN
	JOBUUO, AND JUMPS TO APPROPRIATE TABLE ENTRY WITH ALL AC'S OK.

	S$$UDU CAN BE USED TO DYNAMICALLY DEFINE NEW UUO'S, AND IT
CONTAINS XWD NEXT AVAILABLE OPCODE, TABLE ENTRY POINTER/

S$$UUL:	JSR	.	; USED TO INITIALIZE .JB41
	EXCH	R10,S$$UUL	; SAVE R10, GET PC
	HRRZM	R10,S$$UPC	; SAVE PC
	HLRZ	R10,.JBUUO	; GET OPCODE
	LSH	R10,-9
	HRLI	R10,S$$UUL	; SET UP FOR JRA
	JRA	R10,S$$UDU(R10)	; RESTORE R10 AND GO TO TABLE ENTRY
S$$UDU:	XWD	NXTUUO,.+NXTUUO	; NEXT ALLOWABLE UUO DEFINITION
	JRST	LUFERR	; UNCONDITIONALLY FATAL ERROR
	JRST	LCFERR	; CONDITIONALLY FATAL ERROR
	JRST	LFCALV	; FUNCTION CALL FOR VALUE
	JRST	LFCALN	; FUNCTION CALL FOR NAME
	JRST	LDASGN	; DEDICATED ASSIGNMENT
	JRST	LDCONC	; DEDICATED CONCATENATION
	JRST	LDICNV	; DEDICATED INTEGER CONVERSION
	JRST	LDRCNV	; DEDICATED REAL CONVERSION
	JRST	LAREFV	; ARRAY/TABLE REFERENCE FOR VALUE
	JRST	LAREFN	; ARRAY/TABLE REFERENCE FOR NAME

	NXTUUO=.-S$$UDU
	REPEAT	^O40-NXTUUO,
<	JRST	ERRUUO>	; REMAINING UUO'S INITIALLY UNDEFINED
ERRUUO:	MOVE	R10,[UFERR 1,S$$UPC]	; SET UP ERROR/TYPE POINTER
	MOVEM	R10,.JBUUO	; FAKE
	JRST	LUFERR	; UNCONDITIONALLY FATAL ERROR
; STORAGE
	VARDEF	S$$UPC,1
	SUBTTL	INTERRUPT HANDLER

	COMMENT/ THE FOLLOWING INTERRUPTS ARE TRAPPED:
PUSHDOWN OVERFLOW- THE STACK THAT HAS OVERFLOWED IS EXTENDED
MEMORY PROTECTION VIOLATION- INPUT OR OUTPUT IS PERFORMED IF INST.
	IS A MOVE OR MOVEM AND ILL ADDR IS AN INDEX IN ASSOC. TABLE
FLOATING POINT AND ARITH METIC OVERFLOW- DIVIDE CHECK OR ARITHMETIC
	OVERFLOW CAUSES UNCONDITIONALLY FATAL ERROR

	R1 IS SAVED IN .JBCNI/

INTRUP:	EXCH	R1,.JBCNI	; GET CONDITIONS AND SAVE R1
	ANDI	R1,^O220110	; MASK APPROPRIATE BITS
	CAIGE	R1,^O200000	; IS IT PUSHDOWN OVERFLOW?
	JRST	INTRU1	; NO
	SKIPN	GARBCL	; IS GARBAGE COLLECT FLAG ON?
	JRST	STKOVF	; NO, NORMAL STACK OVERFLOW
	JRST	GRBOVF	; YES, GARBAGE COLLECT STACK OVERFLOW
INTRU1:	CAIL	R1,^O20000	; IS IT MEMORY PROTECTION VIOLATION?
	JRST	VIOASO	; YES, GO DO I/O
	JSP	R1,.+1	; NO, ARITH OVERFLOW, GET FLAGS
	TLNE	R1,1B30	; IS NO DIVIDE OFF?
	UFERR	14,.JBTPC	; NO, DIVIDE CHECK ERROR
	UFERR	15,.JBTPC	; YES, ARITHMETIC OVERFLOW ERROR
	SUBTTL	STACK OVERFLOW

	COMMENT/ HANDLES OVERFLOW OF SS,ES,PS,AS,AND CS DUE TO A PUSH
OR A PUSHJ BY ACQUIRING A NEW STORAGE BLOCK EQUAL TO THE SIZE OF THE
CURRENT ONE PLUS THE EXTENSION SIZE, AND COPYING THE VALID CONTENTS.
THE OLD BLOCK IS RELEASED, THE STACK POINTER AND STACK BASE WORD CHANGED/

STKOVF:	MOVE	R1,.JBTPC	; SAVE NEXT INSTRUCTION ADDR
	HRRM	R1,STKRST+1	; IN CASE OF A NESTED INTERRUPT
	MOVE	R1,[MOVE SS,STKREG]	; GET INSTR TO SAVE SS
	JUMPGE	SS,STKSAV	; SS HAS OVERFLOWED
	SUB	R1,[Z SS-ES,]	; CHANGE TO SAVE ES (OR PS)
	JUMPGE	ES,STKSAV	; ES (OR PS) HAS OVERFLOWED
	SUB	R1,[Z ES-AS,]	; CHANGE TO SAVE AS
	JUMPGE	AS,STKSAV	; AS HAS OVERFLOWED
	SUB	R1,[Z AS-CS,]	; CHANGE TO SAVE CS
	JUMPGE	CS,STKSAV	; CS HAS OVERFLOWED
STKERR:	UFERR	1,STKRST+1	; ERROR, UNKKNOWN STACK OVERFLOW
STKSAV:	MOVEM	R1,STKRST	; EXECUTED TO RELOAD REGISTER ON RETURN
	TLO	R1,^O2000	; CHANGE TO A MOVEM INSTR
	XCT	R1	; AND EXECUTE IT
	MOVE	R1,.JBCNI	; RESTORE R1
	MOVEM	R9,STKSRG+9	; SAVE R0-R9
	HRRZI	R9,STKSRG
	BLT	R9,STKSRG+8
	MOVE	R7,STKREG	; GET CONTENTS OF STACK REGISTER
	MOVE	R8,1(R7)	; GET SIZE, STACK BASE WORD POINTER
	HLRZ	R0,R8	; GET STACK BLOCK SIZE
	MOVEI	R8,(R8)	; XWD 0,STACK BASE WORD POINTER
	CAIL	R8,SSBA	; IS IT ONE OF KNOWN STACK BASE WORDS?
	CAILE	R8,CSBA
	JRST	STKERR	; NO, ERROR
	MOVE	R9,(R8)	; GET STACK BASE WORD
	SUB	R7,R9	; FORM STACK POINTER - BASE
	MOVEM	R7,STKREG	; SAVE REL POINTER
	MOVE	R7,(R9)	; GET CONTENTS OF FIRST WORD OF STACK BLOCK
	TLC	R7,3B19	; CHANGE MARK BITS TO RETURNABLE
	ADDI	R0,(R7)	; ADD EXTENSION SIZE
	JSP	R6,S$$GNS	; GET NEW BLOCK
	MOVEM	R7,(R9)	; MAKE OLD BLOCK RETURNABLE
	HRRM	R7,(R1)	; SAVE EXTENSION SIZE
	HRL	R8,R0	; FORM LAST WORD OF NEW BLOCK WITH NEW SIZE
	MOVE	R2,R0	; GET NEW SIZE
	MOVNI	R3,-2(R2)	; GET -(NEWSIZE-2)
	HRLI	R1,(R3)	; FORM NEW BASE WORD
	MOVEM	R1,(R8)	; SAVE IN BASE WORD LOC
	ADDM	R1,STKREG	; UPDATE STACK POINTER WITH NEW BASE
	HRLI	R1,(R9)	; GET POINTER TO OLD BLOCK
	ADDI	R2,-1(R1)	; GET POINTER TO LAST WORD OF NEW BLOCK
	MOVEM	R8,(R2)	; SAVE SIZE, BASE WORD POINTER
	MOVE	R2,STKREG	; GET LAST VALID STACK ENTRY IN NEW
	AOBJP	R1,.+1	; BLOCK, AND START AT SECOND WORD OF OLD AND NEW
	BLT	R1,(R2)	; BLOCKS TO TRANSFER ALL VALID STACK ENTRIES
	HRLZI	R9,STKSRG	; RESTORE R0-R9
	BLT	R9,R9
STKRST:	.-.		; RESTORE STACK REGISTER
	JRST	.-.	; CONTINUE
; STORAGE
	VARDEF	STKREG,11	; TEMPORARY STACK REGISTER
	STKSRG=STKREG+1		; TEMPS FOR R0-R9
	SUBTTL	FREE STORAGE

	ENTRY	S$$GRS,S$$GNS,S$$MRS,S$$MNS,S$$GCL

	COMMENT/ THE FREE STORAGE SECTION PROVIDES EXTERNAL ENTRIES
FOR ACQUIRING RETURNABLE OR NONRETURNABLE BLOCKS, MAKING BLOCKS RETUR-
NABLE OR NONRETURNABLE, AND FOR FORCING A GARBAGE COLLECTION. IN ADDI-
TION, IT CONTAINS THE GARBAGE COLLECTION ROUTINES,AND TWO MODES OF
STORAGE ACQUISITION: THE FIRST, CALLED QUICKMODE, IS VERY EFFICIENT
AND OPERATES UNTIL THE INITIAL CORE ALLOCATION IS EXHAUSTED; THEN A
GARBAGE COLLECTION OCCURS, AND THE NORMAL MODE IS ENTERED, WHICH MAKES
USE OF AVAILABLE BLOCK LISTS AND EXPANDS CORE WHEN NECESSARY.

	GET RETURNABLE STORAGE
CALL:	JSP	R6,S$$GRS; WITH SIZE IN R0, RETURNS 0,PTR IN R1 WITH
	R0 UNCHANGED

	GET NONRETURNABLE STORAGE
CALL:	JSP	R6,S$$GNS	;SAME AS S$$GRS, BUT BLOCK IS MARKED
	SO THAT IT CAN'T BE COLLECTED

	MAKE RETURNABLE (NONRETURNABLE) STORAGE
CALL:	JSP	R6,S$$MRS(0R S$$MNS)	; WITH POINTER IN R1, MARKS
	BLOCK APPROPRIATELY, AND LEAVES R1 UNCHANGED

	FORCE GARBAGE COLLECTION
CALL:	JSP	R6,S$$GCL	; WITH 0 IN R0, FORCES GARBAGE COLLEC-
	TION, AND RETURNS TOTAL AMOUNT OF WORDS AVAILABLE IN R1 AND
	SIZE OF LARGEST AVAILABLE BLOCK IN R2/
; GET RETURNABLE AND NONRETURNABLE STORAGE
S$$GRS:	JSP	R2,QUICKM	; REPLACED WITH JSP R2,S$$GNS+1 IN NOR-
S$$GNS:	JSP	R2,QUICKM	; MAL MODE (AFTER FIRST GARB COL)
	SUBI	R2,S$$GRS	; FORM INDEX OF 1 OR 2
	JFFO	R0,.+1	; COUNT NUMBER OF LEADING ZEROS
	LSH	R1,1	; *2
	MOVEM	R1,SLOT1	; SAVE FIRST SLOT INDEX
GRBTRY:	HLRZ	R3,AVAIL(R1)	; GET SLOT COUNT
	SOJL	R3,NXTSIZ	; QUIT IF ZERO
	HLRZ	R4,AVAIL+1(R1)	; GET ROVER POINTER
	HLRZ	R5,(R4)	; GET BLOCK SIZE
	CAIG	R0,(R5)	; IS IT BIG ENOUGH?
	JRST	FOUNDS	; YES, USE THIS BLOCK
	SOJL	R3,NXTSIZ	; NO, QUIT IF SLOT COUNT WAS 1
TRYLOP:	HRRZ	R4,(R4)	; GET NEXT BLOCK POINTER
	CAIN	R4,AVAIL(R1)	; IS IT THE AVAIL ARRAY?
	HRRZ	R4,(R4)	; YES, GET NEXT BLOCK POINTER
	HLRZ	R5,(R4)	; NO, GET BLOCK SIZE
	CAIG	R0,(R5)	; IS IT BIG ENOUGH?
	JRST	[HLRZ	R3,AVAIL(R1)
		 SOJA	R3,FOUNDS]	; YES, GET SLOT COUNT - 1
	SOJGE	R3,TRYLOP	; DECREMENT SLOT COUNT, LOOP IF ANY LEFT
	HRLM	R4,AVAIL+1(R1)	; UPDATE ROVER POINTER
NXTSIZ:	SUBI	R1,2	; NEXT LARGER SLOT
	CAIGE	R1,40	; OFF THE END OF THE AVAIL ARRAY?
	JRST	GRBCOL	; YES, NO BLOCKS LEFT, DO GARBAGE COLLECTION
	HLRZ	R3,AVAIL(R1)	; NO, GET SLOT COUNT
	SOJL	R3,NXTSIZ	; QUIT IF ZERO
	HLRZ	R4,AVAIL+1(R1)	; GET ROVER POINTER
	HLRZ	R5,(R4)	; GET BLOCK SIZE
FOUNDS:	HRLM	R3,AVAIL(R1)	; UPDATE SLOT COUNT (OLD COUNT - 1)
	SOJL	R3,ALLGON	; SKIP ROVER UPDATE IF ZERO
	HRRZ	R3,(R4)	; GET NEXT BLOCK POINTER
	CAIN	R3,AVAIL(R1)	; IS IT THE AVAIL ARRAY?
	HRRZ	R3,(R3)	; YES, GET NEXT BLOCK POINTER
	HRLM	R3,AVAIL+1(R1)	; NO, UPDATE ROVER POINTER
ALLGON:	EXCH	R4,R1	; EXCHANGE SLOT INDEX, BLOCK POINTER
	HRLZ	R3,R0	; GET DESIRED BLOCK SIZE INTO LH
	LSH	R3,2	; SET MARK BITS IN BITS 0 AND 1
	LSHC	R2,-2
	EXCH	R3,(R1)	; EXCHANGE WITH FIRST WORD OF ACTUAL BLOCK
	MOVE	R2,1(R1)	; GET BACK LINK FROM ACTUAL BLOCK
	HRRM	R3,(R2)	; SET FORWARD LINK IN PREVIOUS BLOCK
	HRRM	R2,1(R3)	; SET BACK LINK IN NEXT BLOCK
	MOVEI	R3,(R5)	; GET ACTUAL BLOCK SIZE
	MOVE	R2,R0	; GET DESIRED BLOCK SIZE
	SUBI	R3,(R2)	; DIFFERENCE IN SIZE
	JUMPE	R3,(R6)	; RETURN IF ZERO
	ADDI	R2,(R1)	; REMAINDER BLOCK POINTER
	SKIPE	SLFR	; SKIP HEURISTIC IF &SLOWFRAG IS NOT ON
	CAME	R4,SLOT1	; IS THE CURRENT SLOT=INITIAL SLOT?
	CAIG	R3,1	; NO, ARE THERE < 2 WORDS LEFT?
	JRST	.+2	; SAME SLOT OR < 2 WORDS LEFT
	JRST	ADDLST	; NEITHER ADD REMAINDER BLOCK TO AVAIL LIST
	HRLZI	R4,1B19(R3)	; MAKE REMAINDER BLOCK INERT, WILL BE
	MOVEM	R4,(R2)	; COLLECTED LATER
	JRST	(R6)	; RETURN

; ADDLST ADDS A BLOCK TO THE APPROPRIATE AVAIL LIST.
; CALL:	JSP	R6,ADDLST	; WITH PTR IN R2 AND SIZE IN R3, LEAVES
;  R0 AND R1 UNCHANGED
ADDLST:	JFFO	R3,.+1	; COUNT NUMBER OF LEADING ZEROS
	LSH	R4,1	; *2, = SLOT INDEX OF BLOCK
	MOVEI	R4,AVAIL(R4)	; POINTER TO AVAIL ARRAY ENTRY
	MOVE	R5,(R4)	; SLOT COUNT, FIRST BLOCK POINTER
	HRRM	R2,1(R5)	; SET BACK LINK OF FIRST BLOCK
	HRLI	R3,(R5)	; GET FIRST BLOCK POINTER IN LH
	MOVSM	R3,(R2)	; SET SIZE, FORWARD LINK IN NEW BLOCK
	HRRZM	R4,1(R2)	; SET BACK LINK IN NEW BLOCK
	AOBJP	R5,.+1	; INCREMENT SLOT COUNT
	HRRI	R5,(R2)	; SET FIRST BLOCK PTR TO NEW BLOCK
	MOVEM	R5,(R4)	; AND SAVE IN AVAIL ARRAY
	HRLM	R2,1(R4)	; SET ROVER POINTER TO NEW BLOCK
	JRST	(R6)	; RETURN

; MAKE RETURNABLE AND NONRETURNABLE STORAGE
S$$MRS:	JSP	R2,S$$MNS+1	; RETURNABLE, INDEX=1
S$$MNS:	JSP	R2,S$$MNS+1	; NONRETURNABLE, INDEX=2
	MOVEI	R3,(R1)	; GET PTR WITH LH=0
	CAML	R3,MINCOR	; BELOW MINIMUM?
	CAMLE	R3,MAXCOR	; OR ABOVE MAXIMUM?
	JRST	(R6)	; YES, FORGET IT
	SUBI	R2,S$$MRS	; NO, FORM INDEX
	DPB	R2,MRKPTR	; STORE INTO MARK BITS
	JRST	(R6)	; RETURN
MRKPTR:	POINT	2,(R1),1	; FIRST TWO BITS POINTED TO BY R1

; FORCE GARBAGE COLLECTION
S$$GCL:	MOVEM	R0,BLSIZE	; SAVE SIZE
	JRST	QUICKO+3	; INITIALLY QUICKMODE, LATER CHANGED TO
		; JRST GRBCOL+2
; QUICKMODE STORAGE ACQUISITION ROUTINES, WHICH OVERLAY THEMSELVES
; WITH THE AVAIL LIST WHEN SWITCHING MODES
	AVAIL=.-36	; DEFINE REAL PART OF AVAIL LIST AS STARTING HERE
QUICKM:	SUBI	R2,S$$GRS	; FORM MARK BITS
	MOVE	R1,CURCOR	; GET CURRENT LOCATION
	MOVE	R3,R0	; GET SIZE
	ADDI	R3,(R1)	; COMPUTE NEXT LOCATION
	CAMLE	R3,MAXFRE	; WITHIN BOUNDS?
	JFFO	R0,QUICKO	; NO, QUICKMODE OVERFLOW
	MOVEM	R3, CURCOR	; YES, NEW CURRENT LOC
	IOR	R0,MRKTB1(R2)	; SET MARK BITS
	HRLZM	R0,(R1)	; STORE MARK BITS, SIZE IN LH
	ANDI	R0,^O177777	; CLEAR MARK BITS
	JRST	(R6)	; RETURN
QUICKO:	LSH	R1,1	; COMPUTE SLOT
	MOVEM	R0,BLSIZE	; SAVE SIZE
	MOVEM	R2,BLTYPE	; SAVE MARK TYPE
	EXCH	R1,SLOT1	; SAVE SLOT NUMBER, GET CURCOR
	MOVE	R3,MAXFRE	; DETERMINE AMOUNT LEFT
	SUBI	R3,(R1)
	HRLZI	R4,1B19(R3)	; CREATE INERT BLOCK
	MOVEM	R4,(R1)	; STARTING AT CURRENT LOC
	MOVEI	R3,S$$GNS+1	; UPDATE ENTRY POINTS
	HRRM	R3,S$$GRS
	HRRM	R3,S$$GNS
	MOVE	R5,AVLWRD	; GET INDEX WORD FOR AVAIL INITIALIZATION
	HRLZI	R4,AVLOOP	; MOVE AVLOOP INTO R0-R4
	BLT	R4,R4
	MOVEM	R4,S$$GCL+1	; UPDATE GARB COL ENTRY
	JRST	0	; START LOOP
AVLOOP:	PHASE	0
	HRRZM	R5,(R5)	; R0: STORE FORWARD LINK
	HRRZM	R5,1(R5)	; R1: STORE BACKWARD LINK
	AOBJN	R5,.+1	; R2: BUMP COUNT
	AOBJN	R5,.-3	; R3: BUMP COUNT, LOOP IF NOT YET FINISHED
	JRST	GRBCOL+2	; R4: FINISHED, PROCEED WITH GARB COL
	DEPHASE
AVLWRD:	XWD	-34,AVAIL+36	; PRESET 34 WORDS WITH FORWARD AND BACK
	BLOCK	AVAIL+70-.	; ALLOW FOR FULL 34 WORDS
GARBCL:	0	; USE BOTH AS FLAG AND 35TH WORD (SIZE 1)
	MRKTB1=.-1
	1B19	; MARK BITS=1
	2B19	; MARK BITS=2
	COMMENT/ GARBAGE COLLECTION
SAVE SIZE, TYPE, AND LINK. SET GARBCL FLAG AND INITIALIZE GARBAGE STACK.
MARK BLOCKS POINTED TO BY PROGRAM VARIABLES, GLOBAL VARIABLES, AND
VALUES ON ES, AND BY ELEMENTS OF NONTERMINAL DATATYPE VALUES. COLLECT
ALL UNUSED BLOCKS AND RETURN THEM TO THE AVAIL LIST, COUNTING THE TOTAL
CORE AVAILABLE AND RETAINING THE LARGEST AVAILABLE BLOCK SIZE FOUND.
GET THE BLOCK (IF REQUESTED), EXPANDING CORE IF NECESSARY. COMPUTE
DENSITY EXTENSION, EXPANDING CORE IF NECESSARY. RESET GARBCL FLAG AND
RETURN/

GRBCOL:	MOVEM	R0,BLSIZE	; SAVE BLOCK SIZE
	MOVEM	R2,BLTYPE	; SAVE MARK TYPE
	MOVEM	R6,BLLINK	; SAVE PROGRAM LINK
	SETOM	GARBCL	; SET GARBAGE COLLECTION FLAG
	MOVN	R6,GARSIZ	; SET UP GARBAGE STACK (FOR MARKING)
	HRL	R6,MAXFRE	; IN R6, RUNNING FROM MAXFRE TO .JBREL,
	MOVS	R6,R6	; OF SIZE GARSIZ+1
	SUB	R6,[XWD 1,1]	; IOWD GARSIZ+1,MAXFRE
; START MARKING BY DETERMINING NUMBER OF ELEMENTS ON ES AND MARKING THEM
	HRLZI	R0,1B18	; MARK BIT FOR USED BLOCKS
	MOVN	R5,ESSA	; GET - ES SAVED -(M,M)
	MOVE	R4,ESBA	; AND ES BASE
	HLRE	R1,ES	; GET -NO OF REMAINING ELEMENTS ON ES
	MOVN	R1,R1	; MAKE POSITIVE
	JUMPL	R1,GETESB	; IF <0, MUST BE IN FORTRAN, USE ES SAVED
	ADDI	R1,1(ES)	; ADDRESS OF LAST WORD OF STACK
	CAMLE	R1,MAXCOR	; WITHIN CORE BOUNDS?
	JRST	GETESB	; NO, MUST BE IN FRORTRAN, USE ES SAVED
	HRRZ	R2,(R1)	; GET BASE WORD POINTER
	CAIE	R2,ESBA	; DOES BASE WORD POINTER POINT TO ES BASE WORD?
	JRST	GETESB	; NO, ES IS NOT CURRENT, USE ES SAVED
	MOVN	R5,ES	; YES, COMPUTE - ES CURRENT
	ADD	R5,R4
GETESB:	HRRI	R5,(R4)	; -M, PTR TO FIRST ENTRY
	AOBJP	R5,.+2	; SKIP IF NOTHING ON STACK
	PUSHJ	R6,MRKMLT	; MARK EACH VALUE FROM BOTTOM TO TOP
; MARK VALUES OF EACH VARIABLE ON VARIABLE BLOCK LIST
	HLRZ	R1,GLVL	; GET FIRST BLOCK POINTER
MRKGLV:	PUSH	R6,(R1)	; SAVE NEXT BLOCK POINTER
	HLRZ	R5,(R1)	; GET -(BLOCKSIZE-1) INTO RH
	MOVNI	R5,-1B18-1(R5)
	HRLI	R5,1(R1)	; AND BLOCK PTR + 1 IN LH
	MOVS	R5,R5	; SWITCH
	PUSHJ	R6,MRKMLT	; MARK EACH VALUE IN BLOCK
	POP	R6,R1	; RESTORE NEXT BLOCK POINTER
	TRNE	R1,-1	; IS IT ZERO?
	JRST	MRKGLV	; NO, LOOP FOR EACH VARIABLE BLOCK ON CHAIN
; CORE MAY HAVE EXPANDED DURING MARKING PHASE
	MOVE	R1,.JBREL	; HAS CORE EXPANDED?
	CAMN	R1,MAXCOR
	JRST	STRAVL	; NO, SKIP
	SUB	R1,GARSIZ	; YES, COMPUTE NEW MAXFRE
	EXCH	R1,MAXFRE	; EXCHANGE WITH OLD ONE
	MOVE	R2,MAXFRE	; COMPUTE DIFFERENCE
	SUBI	R2,(R1)
	HRLZI	R2,1B19(R2)	; CREATE FIRST WORD OF INERT BLOCK
	MOVEM	R2,(R1)	; BETWEEN OLD AND NEW VALUES OF MAXFRE
; START COLLECTION, INITIALIZE PARAMETERS
STRAVL:	TLO	R0,1	; PSEUDO 1-WORD NONRETURNABLE BLOCK
	MOVEM	R0,@MAXFRE	; MARK MAXFRE TO DELIMIT COLLECTION AREA
	SETZM	AVLCOR	; TOTAL CORE AVAILABLE
	SETZM	BIGBLK	; BIGGEST BLOCK AVAILABLE
	SETZM	LSTBLK	; LAST AVAILABLE BLOCK POINTER
	SETZ	R0,	; INITIAL SIZE
	MOVE	R1,MINCOR	; INITIAL PTR
; ACCUMULATION LOOP, CLEAR ACCUMULATION PARAMETERS
CLRAVL:	SETZM	AVLPTR	; AVAILABLE BLOCK POINTER
	SETZM	AVLSIZ	; AVAILABLE BLOCK SIZE
	SETZM	AVLCNT	; AVAILABILITY INDICATOR
; CONSECUTIVE BLOCK LOOP, INCREMENT POINTER
NXTAVL:	ADD	R1,R0	; PTR_PTR+SIZE
	CAMLE	R1,MAXFRE	; IS PTR > MAXFRE?
	JRST	COLFIN	; YES, STOP COLLECTING
	SETZ	R2,	; GET MARK TYPE OF PTR
	HLLZ	R3,(R1)
	LSHC	R2,2
	LSH	R3,-2	; GET SIZE OF POINTER
	HLRZ	R0,R3
	JRST	.+1(R2)	; JUMP TO APPROPRIATE ACTION
	JRST	AVLAVL	; MARK=00, ON AVAIL LIST
	JRST	AVLFRE	; MARK=01, AVAILABLE
	JRST	GATHER	; MARK=10, NONRETURNABLE
	TLO	R3,1B19	; MARK=11, MARKED, RESET TO 01
	HLLM	R3,(R1)	; AND STORE WITH SIZE IN FIRST WORD OF BLOCK
GATHER:	MOVE	R2,AVLCNT	; GET AVAILABILITY INDICATOR
	JUMPE	R2,NXTAVL	; IF 0, GO ON TO NEXT BLOCK
	JUMPL	R2,UPDAVL	; IF<0, UPDATE STATISTICS
	MOVE	R3,AVLSIZ	; IF>0, GET ACCUMULATED SIZE
	CAIN	R3,1	; IS IT JUST 1?
	JRST	CLRAVL	; YES, IGNORE BLOCK AS IF IT WERE MARKED
	MOVE	R2,AVLPTR	; NO, GET ACCUMULATED BLOCK POINTER
	CAIL	R3,1B19	; IS BLOCK TOO BIG?
	JSP	R6,ADDBBB	; YES, BREAK IT UP
	JSP	R6,ADDLST	; NO, ADD TO AVAIL LIST
UPDAVL:	MOVE	R3,AVLSIZ	; GET ACCUMULATED SIZE
	ADDM	R3,AVLCOR	; ADD TO TOTAL CORE AVAILABLE
	MOVE	R2,AVLPTR	; GET ACCUMULATED BLOCK POINTER
	MOVEM	R2,LSTBLK	; SAVE PTR AS LAST BLOCK AVAILABLE
	CAMLE	R3,BIGBLK	; BIGGER THAN BIGGEST?
	MOVEM	R3,BIGBLK	; YES, USE INSTEAD
	JRST	CLRAVL	; LOOP
AVLAVL:	SKIPE	AVLCNT	; IS INDICATOR 0?
	JRST	REMPRE	; NO, DISCONNECT PRESENT BLOCK
	MOVNM	R0,AVLCNT	; YES, SET INDICATOR<0
BEGAVL:	MOVEM	R0,AVLSIZ	; INITIALIZE SIZE
	MOVEM	R1,AVLPTR	; AND BLOCK POINTER FOR ACCUMULATION
	JRST	NXTAVL	; LOOP
AVLFRE:	SKIPE	R2,AVLCNT	; IS INDICATOR 0? (R2_INDICATOR)
	JRST	REMPR1	; NO, GO ACCUMULATE
	MOVEM	R0,AVLCNT	; YES, SET INDICATOR>0
	JRST	BEGAVL	; INITIALIZE ACCUMULATION
REMPRE:	MOVE	R3,R0	; PRESENT BLOCK SIZE
	MOVE	R2,R1	; PRESENT BLOCK POINTER
	JSP	R6,REMLST	; DISCONNECT
	MOVE	R2,AVLCNT	; RELOAD INDICATOR
REMPR1:	JUMPGE	R2,REMPR2	; SKIP OVER IF >0
	MOVE	R2,AVLPTR	; LAST PTR
	MOVE	R3,AVLSIZ	; LAST SIZE
	JSP	R6,REMLST	; DISCONNECT
	MOVEM	R0,AVLCNT	; SET INDICATOR>0
REMPR2:	ADDM	R0,AVLSIZ	; INCREASE AVAILABLE BLOCK SIZE
	JRST	NXTAVL	; LOOP

; REMLST REMOVES A BLOCK FROM THE AVAIL LIST
; CALL:	JSP	R6,REMLST	; WITH POINTER IN R2 AND SIZE IN R3,
;  LEAVES R0 AND R1 UNCHANGED
REMLST:	MOVE	R4,(R2)	; FORWARD LINK
	MOVE	R5,1(R2)	; BACK LINK
	HRRM	R5,1(R4)	; BACK LINK IN FORWARD BLOCK
	HRRM	R4,(R5)	; FORWARD LINK IN BACK BLOCK
	JFFO	R3,.+1	; COMPUTE SLOT INDEX
	LSH	R4,1
	HRLZI	R5,-1	; DECREMENT SLOT COUNT
	ADDB	R5,AVAIL(R4)	; AND GET FIRST BLOCK PTR
	HRLM	R5,AVAIL+1(R4)	; RESET ROVER POINTER TO FIRST BLOCK
	JRST	(R6)	; RETURN

; ADDBBB ADDS THE PIECES OF AN OVERSIZE BLOCK TO THE AVAIL LIST
; CALL:	JSP	R6,ADDBBB	; WITH POINTER IN R2 AND SIZE IN R3,
;	JSP	R6,ADDLST	; LEAVES R0 AND R1 UNCHANGED
ADDBBB:	HRRM	R6,BBBRET	; SAVE LINK
BBBLOP:	MOVEI	R4,(R3)	; GET SIZE
	SUBI	R4,1B19-1	; REDUCE IT BY MAXIMUM PERMISSIBLE
	HRRM	R4,LODSIZ	; SAVE REDUCED SIZE
	MOVEI	R4,(R2)	; GET PTR
	ADDI	R4,1B19-1	; NEXT POINTER
	HRRM	R4,LODPTR	; SAVE IT
	MOVEI	R3,1B19-1	; SIZE OF CURRENT BLOCK
	JSP	R6,ADDLST	; ADD TO AVAIL LIST
LODSIZ:	MOVEI	R3,.-.	; RESTORE SIZE
LODPTR:	MOVEI	R2,.-.	; RESTORE POINTER
	CAIL	R3,1B19	; IS SIZE STILL TOO BIG?
	JRST	BBBLOP	; YES, LOOP
	CAILE	R3,1	; NO, IS SIZE>1?
BBBRET:	JRST	.-.	; YES, RETURN AND DO A\DDLST
	AOS	R6,.-1	; BUMP RETURN LINK BEYORD ADDLST
	JUMPE	R3,(R6)	; RETURN IF ZERO
	HRLZI	R5,1B19+1	; CREATE INERT BLOCK OF SIZE 1
	MOVEM	R5,(R2)
	JRST	(R6)	; RETURN
; COLLECTION OVER, GET DESIRED BLOCK
COLFIN:	MOVE	R0,BLSIZE	; GET BLOCK SIZE
	JUMPE	R0,DNSCHK	; IF 0 (FORCED COLLECTION) GO TO DENSITY
	CAMLE	R0,BIGBLK	; IS SIZE>LARGEST AVAILABLE?
	JRST	MORCOR	; YES, MUST EXPAND CORE
	MOVE	R1,SLOT1	; NO, GET SLOT INDEX
	MOVE	R2,BLTYPE	; AND MARK TYPE
	JSP	R6,GRBTRY	; SIMULATE GET BLOCK CALL
	MOVEM	R1,BLPOIN	; SAVE POINTER
	JRST	DNSCHK	; GO ON TO DENSITY CHECK
; EXPAND CORE TO GET ENOUGH FOR DESIRED BLOCK
MORCOR:	MOVE	R2,MAXFRE	; GET FREE CORE TOP BOUNDARY
	HLRZ	R3,@LSTBLK	; GET SIZE OF LAST BLOCK MADE AVAILABLE
	SUBI	R2,(R3)	; AND SUBTRACT FROM TOP BOUNDARY
	CAME	R2,LSTBLK	; IS IT THE SAME LOC AS LAST BLOCK?
	JRST	MORCR1	; NO, FORGET IT
	MOVEM	R2,MAXFRE	; YES, MOVE BOUNDARY DOWN
	SUBM	R3,AVLCOR	; SUBTRACT SIZE FROM TOTAL CORE AVAILABLE
	MOVNS	AVLCOR
	JSP	R6,REMLST	; DISCONNECT, TO BE USED AS FIRST PART
				; OF NEW ONE
MORCR1:	MOVE	R2,MAXFRE	; COMPUTE NEW MAX CORE BOUNDARY
	ADD	R2,R0	; NEEDED FOR NEW BLOCK
	ADD	R2,GARSIZ	; AND GARBAGE STACK
	JSP	R6,EXPCOR	; EXPAND CORE
	UFERR	4,PRGLNK	; ERROR IF CANNOT
	MOVE	R2,MAXFRE	; PTR TO NEW BLOCK
	HRRZ	R3,R0	; FORM FIRST WORD WITH MARK BITS AND SIZE
	MOVE	R4,BLTYPE
	IOR	R3,MRKTB1(R4)
	HRLZM	R3,(R2)
	MOVEM	R2,BLPOIN	; SAVE POINTER
	ADD	R2,R0	; FIRST AVAILABLE LOC
	MOVE	R3,.JBREL	; COMPUTE LAST AVAILABLE LOC
	SUB	R3,GARSIZ
	MOVEM	R3,MAXFRE	; SAVE
	SUBI	R3,(R2)	; COMPUTE SIZE IN BETWEEN
	CAIG	R3,1	; IS IT >1?
	JRST	SMLEXT	; NO, IGNORE OR MAKE INERT
	MOVEM	R2,LSTBLK	; YES, SAVE AS LAST AVAILABLE BLOCK
	ADDM	R3,AVLCOR	; ADD TO AVAILABLE STORAGE
	CAMLE	R3,BIGBLK	; BIGGER THAN BIGGEST BLOCK?
	MOVEM	R3,BIGBLK	; YES, USE INSTEAD
	JSP	R6,ADDLST	; ADD TO AVAIL LIST
	JRST	DNSCHK	; GO DO DENSITY CHECK
SMLEXT:	JUMPE	R3,DNSCHK	; SKIP IF ZERO
	HRLZI	R4,1B19+1	; MAKE INERT BLOCK OF 1
	MOVEM	R4,(R2)
; DENSITY CHECK: IF DENSITY IS GREATER THAN SPECIFIED BY &DENSITY
; KEYWORD, CORE IS EXPANDED AS FAR AS POSSIBLE TO ACCOMODATE REQUIREMENT.
;  FORMULA IS: EXT_((100-&DENSITY)*(MAXFRE-MINCOR)-100*AVLCOR)/&DENSITY
; IF EXT>0, EXTEND CORE BY THAT AMOUNT, IF POSSIBLE. IF EXT<0 OR =0,
; REQUIREMENTS ARE ALREADY MET BY CURRENT CORE SIZE
DNSCHK:	MOVE	R2,DENS	; GET KEYWORD VAL
	CAILE	R2,100	; IS IT >100
	MOVEI	R2,100	; YES, 100 IS ENOUGH
	CAIGE	R2,1	; IS IT <1
	MOVEI	R2,1	; YES, MUST BE AT LEAST 1
	MOVEM	R2,DENS	; RESET KEYWORD IF NECESSARY
	SUBI	R2,100	; COMPUTE FORMULA
	MOVE	R3,MINCOR
	SUB	R3,MAXFRE
	IMUL	R2,R3
	MOVE	R3,AVLCOR
	IMULI	R3,100
	SUB	R2,R3
	IDIV	R2,DENS	; RESULT IN R2
	JUMPLE	R2,NOTEXT	; DON'T EXTEND UNLESS >0
	ADD	R2,.JBREL	; NEW MAX CORE LIMIT
	CAIL	R2,^O776000	; INTO LAST 1K BLOCK?
	MOVEI	R2,^O775777	; YES, CAN'T GO THERE
	CORE	R2,	; TRY TO EXPAND
	JRST	PRTEXT	; ONLY PARTIAL EXPANSION
PRTEXR:	MOVE	R2,MAXFRE	; GET LAST FREE CORE MAX
	MOVE	R3,.JBREL	; COMPUTE LATEST
	SUB	R3,GARSIZ
	MOVEM	R3,MAXFRE	; SAVE
	SUBI	R3,(R2)	; SIZE OF BLOCK IN BETWEEN
	ADDM	R3,AVLCOR	; ADD TO AVAILABLE CORE
	CAMLE	R3,BIGBLK	; BIGGER THAN BIGGEST?
	MOVEM	R3,BIGBLK	; YES, USE INSTEAD
	CAIL	R3,1B19	; MAKE SURE IT IS NOT TOO BIG
	JSP	R6,ADDBBB	; TOO BIG, BREAK IT UP
	JSP	R6,ADDLST	; OK, ADD TO AVAIL LIST
; FINISH UP BY TESTING FOR ANY CORE EXPANSION AND RESETTING PARAMETERS
NOTEXT:	MOVE	R2,.JBREL	; GET NEW CORE BOUNDARY
	CAMN	R2,MAXCOR	; SAME AS OLD?
	JRST	GRBFIN	; YES, SKIP
	MOVEM	R2,MAXCOR	; NO, UPDATE PARAMETERS
	MOVE	R2,MAXFRE
	MOVEM	R2,.JBFF
	HRLM	R2,.JBSA
	HRLM	R2,.JBCOR
GRBFIN:	JUMPE	R0,GCLFIN	; DIFFERENT RESULTS IF FORCED COLLECTION
	MOVE	R1,BLPOIN	; LOAD BLOCK POINTER (SIZE ALREADY IN R0)
	SETZM	GARBCL	; CLEAR GARBAGE COLLECT FLAG
	AOS	STATV+1	; INCREMENT GARBAGE COLLECTION COUNT
	JRST	@BLLINK	; RETURN
GCLFIN:	MOVE	R1,AVLCOR	; GET TOTAL CORE AVAILABLE
	MOVE	R2,BIGBLK	; AND BIGGEST BLOCK
	JRST	GRBFIN+2	; AND EXIT
; PARTIAL CORE EXTENSION, SWITCH DENSITY CHECK AND CORE EXPANSION CHECK
; OUT ONCE CORE HAS REACHED SYSTEM-ALLOWED LIMIT
PRTEXT:	MOVE	R3,NOTEXT+2	; GET [JRST GRBFIN]
	MOVEM	R3,DNSCHK	; SWITCH OUT INTERVENING CODE
	LSH	R2,10	; NUMBER OF CORE BLOCKS*^O2000
	SUBI	R2,1	; -1=LAST WORD
	CAME	R2,.JBREL	; ANYTHING LEFT TO GAIN?
	CORE	R2,	; YES, EXTEND CORE
	JRST	NOTEXT	; NO, OR ERROR, SKIP TO FINISH
	JRST	PRTEXR	; ADD NEW CORE TO SYSTEM
	COMMENT/ MARK MULTIPLE ELEMENT BLOCK
CALL:	PUSHJ	R6,MRKMLT	; WITH -COUNT,FIRST PTR IN R5
	IF A VALUE POINTS TO A FREE STORAGE BLOCK THAT IS NOT MARKED,
IT IS MARKED. IN ADDITION, IF IT IS ITSELF A MULTIPLE ELEMENT BLOCK,
MRKMLT IS CALLED RMCURSIVELY ON IT. R0 CONTAINS 1B0, USED FOR MARKING,
AND IS UNCHANGED/

MRKMLT:	MOVE	R2,(R5)	; GET NEXT ELEMENT DESCRIPTOR
	JUMPL	R2,MRKLOP	; LOOP IF INTEGER OR REAL
	HRRZI	R3,(R2)	; GET DESCR PTR
	CAML	R3,MINCOR	; IS IT WITHIN FREE STORAGE BOUNDS?
	CAML	R3,MAXFRE
	JRST	MRKLOP	; NO, LOOP
	SKIPGE	R4,(R3)	; IS IT ALREADY MARKED? (R4_FIRST WORD)
	JRST	MRKLOP	; YES, LOOP
	SETZ	R1,	; NO
	LSHC	R1,4	; GET DESCR TYPE
	CAIN	R1,4	; IS IT NAME?
	JRST	MRKLOP	; YES, LOOP
	IORM	R0,(R3)	; NO, MARK
	JUMPE	R1,MRKLOP	; LOOP IF STRING
	PUSH	R6,R5	; SAVE BLOCK INDEX, PTR
	XCT	MRKDSC-5(R1)	; PERFORM MARKING PER DESCR TYPE
	POP	R6,R5	; RESTORE BLOCK INDEX, POINTER
MRKLOP:	AOBJN	R5,MRKMLT	; LOOP IF MORE ELEMENTS
	POPJ	R6,	; OR RETURN
; THREE DIFFERENT MULTIPLE ELEMENT DESCRIPTOR TYPES
MRKDSC:	PUSHJ	R6,MRKART	; ARRAY OR TABLE
	JRST	MRKPAT	; PATTERN
	JRST	MRKDAT	; PROGRAMMER-DEFINED DATATYPE
; ARRAY OR TABLE BLOCK
MRKART:	JUMPL	R2,MRKTAB	; DESCRIPTOR BIT 4 = 1, IS TABLE
	SUB	R6,[XWD 1,1]	; ERASE PUSHJ
	MOVE	R5,(R4)	; GET FIRST WORD OF PROTOTYPE BLOCK
	JUMPL	R5,MRKCOM	; SKIP IF PROTOTYPE ALREADY MARKED
	IORM	R0,@(R5)	; MARK PROTOTYPE STRING
	IORM	R0,(R4)	; MARK PROTOTYPE BLOCK
MRKCOM:	HRLZI	R5,(R3)	; GET BLOCK POINTER INTO LH
	HRRI	R5,MRKCNT	; GET 'CONTINUE MARKING' LAB INTO RH
	EXCH	R5,(R6)	; SIMULATE PUSHJ, AND RESTORE R5
	JRST	MRKLOP	; CONTINUE LOOP
MRKCNT:	HLRZ	R5,1(R6)	; NOW MARK ELEMENTS OF BLOCK, GET PTR
	HLRZ	R4,(R5)	; GET -(SIZE) INTO LH OF R5
	TRZ	R4,3B19
	MOVNI	R4,(R4)
	HRLI	R5,(R4)
	AOBJN	R5,MRKMLT	; GO MARK
	POPJ	R6,	; THIS SHOULN'T HAPPEN, BUT QUIT JUST IN CASE
; TABLE BLOCK
MRKTAB:	ADDI	R3,2	; PTR TO EXTENSION WORD OF BASE BLOCK
	PUSH	R6,R3	; SAVE
	HLRZ	R5,-1(R3)	; COMPUTE NEXT AVAILABLE ENTRY POINTER
	MOVE	R4,-1(R3)
	ADDI	R5,(R4)
	PUSH	R6,R5	; SAVE
	HLRZ	R5,(R3)	; COMPUTE END OF CURRENT BLOCK
	ADDI	R5,1(R3)
	PUSH	R6,R5	; SAVE
	MOVEI	R5,1(R3)	; STARTING ENTRY POINTER FOR CURRENT BL
TBMLOP:	CAMN	R5,-1(R6)	; REACHED NEXT AVAILABLE ENTRY?
	JRST	TBMFIN	; YES, FINISHED WITH WHOLE TABLE
	CAMN	R5,(R6)	; NO, REACHED END OF CURRENT BLOCK?
	JRST	TBMNXT	; YES, GO ON TO EXTENSION
	PUSH	R6,R5	; NO, SAVE MARKING POINTER
	ADD	R5,[XWD -2,2]	; SET UP TO MARK KEY AND VALUE DESCRS
	PUSHJ	R6,MRKMLT
	POP	R6,R5	; RESTORE MARKING POINTER
	ADDI	R5,4	; POINT TO NEXT ENTRY
	JRST	TBMLOP	; LOOP, WITH R5=0,NEXT ENTRY PTR
TBMNXT:	HRRZ	R3,@-2(R6)	; GET PTR TO EXT WORD OF EXT BLOCK
	ADDI	R3,1
	MOVEM	R3,-2(R6)	; SAVE BACK IN STACK
	IORM	R0,-1(R3)	; MARK EXTENSION BLOCK
	HLRZ	R5,(R3)	; COMPUTE END OF CURRENT BLOCK
	ADDI	R5,1(R3)
	MOVEM	R5,(R6)	; SAVE BACK IN STACK
	JRST	TBMLOP-1	; RESTART LOOP
TBMFIN:	SUB	R6,[XWD 3,3]	; RESET STACK PTR
	POPJ	R6,	; RETURN
; PATTERN BLOCK
MRKPAT:	MOVEI	R5,-1(R4)	; GET PTR TO FIRST WORD OF PATTERN BLOCK
	CAML	R5,MINCOR	; IS IT WITHIN FREE STORAGE BOUNDS?
	IORM	R0,(R5)	; YES, MARK IT
	JRST	MRKCOM	; NO, AND CONTINUE
; DATATYPE BLOCK
	MRKDAT=MRKCOM	; PROTOTYPE STRING AND LOCATION ARE ALWAYS 
			; MARKED NONRETURNABLE
; EXPAND CORE, TESTING FOR LAST 1K BLOCK LIMIT
; CALL:	JSP	R6,EXPCOR	; WITH NEW CORE LIMIT IN R2, RETURNS
;	TO 0(R6) IF ERROR OR INTO LAST 1K BLOCK, AND TO 1(R6) IF SUC-
;	CESSFUL. LEAVES R0 AND R1 UNCHANGED
EXPCOR:	CAIL	R2,^O776000	; INTO LAST 1K BLOCK?
	JRST	(R6)	; YES, FAIL
	CORE	R2,	; TRY TO EXPAND
	JRST	(R6)	; FAIL
	JRST	1(R6)	; SUCCEED

; GARBAGE COLLECTION STACK OVERFLOW DURING MARKING
; EXPAND CORE BY 1K BLOCK, EXPAND STACK (IN R6) BY SAME AMOUNT, EXPAND
; GARSIZ BY EXTENSION SIZE (P$GBXT), AND RE-EXECUTE PUSH OR PUSHJ
GRBOVF:	MOVE	R1,.JBREL	; GET CURRENT CORE LIMIT
	ADDI	R1,^O2000	; EXPAND BY 1K BLOCK
	CAIGE	R1,^O776000	; BUT NOT INTO LAST 1K OF CORE
	CORE	R1,	; EXPAND
	UFERR	4,PRGLNK	; ERROR
	HRLI	R6,-^O2000	; UPDATED STACK COUNT
	MOVEI	R1,P$GBXT	; GET EXTENSION SIZE
	ADDM	R1,GARSIZ	; MAKE GARBAGE STACK BIGGER IN THE FUTURE
	MOVE	R1,.JBCNI	; RESTORE R1
	JRST	@.JBTPC	; CONTINUE

; STORAGE
GARSIZ:	P$GBUF	; INITIAL GARBAGE COLLECT STACK SIZE
	SLOT1=CURCOR	; SLOT INDEX
	VARDEF	BLSIZE,1	; DESIRED BLOCK SIZE
	VARDEF	BLTYPE,1	; DESIRED BLOCK MARK TYPE
	VARDEF	BLLINK,1	; RETURN LINK
	VARDEF	BLPOIN,1	; DESIRED BLOCK POINTER
	VARDEF	AVLCOR,1	; CUMULATIVE AVAILABLE CORE
	VARDEF	BIGBLK,1	; LARGEST AVAILABLE BLOCK ENCOUNTERED
	VARDEF	LSTBLK,1	; LAST AVAILABLE BLOCK ENCOUNTERED
	VARDEF	AVLPTR,1	; CURRENT AVAILABLE CORE STARTING PTR
	VARDEF	AVLSIZ,1	; CURRENT AVAILABLE BLOCK SIZE
	VARDEF	AVLCNT,1	; AVAILABILITY INDICATOR
	SUBTTL	INPUT AND OUTPUT ASSOCIATION FUNCTIONS

	ENTRY	S$$AST,S$$ASB,S$$IOI,S$$IIX,S$$IOX

	COMMENT" THIS SECTION PERFORMS I/O AS A RESULT OF A MEMORY
PROTECTION INTERRUPT, USING THE ILLEGAL ADDRESS AS AN INDEX IN THE ASSO-
CIATION TABLE. IF THE INSTRUCTION CAUSING THE INTERRUPT IS A MOVE, SETZM,
OR MOVEM, I/O IS PERFORMED PROVIDED THE RESPECTIVE ASSOCIATION EXISTS,
AND THE KEYWORDS &INPUT OR &OUTPUT, RESPECTIVELY, ARE NONZERO.
IF THE INSTRUCTION IS A SETM OR SETAM, OR A MOVE OR MOVEM WITHOUT A
CORRESPONDING ASSOCIATION, THE OPERATION IS COMPLETED USING THE AC-
TUAL VARIABLE ADDRESS, BUT NO I/O IS PERFORMED. ANY OTHER OPCODE OR
ADDRESS BEYOND ASSOCIATION TABLE LIMITS IS AN ADDRESSING ERROR.
	R9 MUST NOT BE USED IN THE EFFECTIVE ADDRESS COMPUTATION,
AND AN INPUT INSTRUCTION MUST NEVER IMMEDIATELY FOLLOW AN OUTPUT
INSTRUCTION ON THE PDP-6 OR KA10."

VIOASO:	MOVE	R1,.JBCNI	; RESTORE R1
	MOVEM	R9,STKSRG+9	; SAVE R9
	IFE	P$KI10,
<	MOVE	R9,GOTINP	; CHANGE RESPONSE TO ILLEGAL ADDR
	MOVEM	R9,VIOASO+1	; DURING THIS COMPUTATION
	MOVE	R9,.JBTPC	; GET POINTER TO INSTR
	HRRM	R9,VIOEXT	; SAVE INSTR POINTER
	MOVE	R9,-1(R9)	; GET ACTUAL INSTRUCTION
	TLZN	R9,1B31	; CLOBBER INDIRECT BIT
	JRST	[HRRI	R9,@R9
		JRST	.+2]	; GET IMMEDIATE IF NOT INDIRECT
	HRR	R9,@R9	; GET FIRST LEVEL EFF ADDR
	TLZ	R9,^O17	; ERASE INDEX FIELD
	HLLZM	R9,VIOINS	; SAVE OP AC,
	MOVEI	R9,(R9)	; CLEAR LH
	CAIGE	R9,^O776000	; IS ADDR IN LAST 1K OF MEMORY?
GOTINP:	JRST	TRYINP	; NO, TRY INPUT POSSIBILITY
	LSH	R9,2	; *4
	ADD	R9,ASOTBL	; + TABLE BASE
	HLLI	R9,	; CLEAR LH
	CAMG	R9,ASOTBT	; LESS THAN TABLE TOP?
	JRST	TRYINP	; YES, TRY INPUT
	MOVEM	R9,VIOENT	; SAVE ENTRY POINTER
	HRRZ	R9,(R9)	; GET VARIABLE POINTER
	HRRM	R9,VIOINS	; SAVE POINTER, GET OP AC,
	MOVE	R9,[MOVEM R9,STKSRG+9]	; CHANGE RESPONSE TO
	MOVEM	R9,VIOASO+1	; ILLEG ADDR BACK TO NORMAL
	HLLZ	R9,VIOINS	; GET OPCODE
	TLZ	R9,^O740
	IFN	P$PDP6,
<	CAMN	R9,[MOVEM]	; IS IT A STORE?>
	IFE	P$PDP6,
<	CAME	R9,[MOVEM]	; IS IT A STORE?
	CAMN	R9,[SETZM]>
	JRST	VIOOUT	; YES, DO OUTPUT
	CAME	R9,[SETAM]	; IS IT STORE W/O OUTPUT?
	JRST	TRYINP	; NO, TRY INPUT
	JRST	VIORET+1	; YES, DO STORE
TRYINP:	MOVE	R9,GOTERR	; CHANGE RESPONSE AGAIN
	MOVEM	R9,VIOASO+1
	AOS	R9,VIOEXT	; BUMP INSTR POINTER, TRY INPUT
	MOVE	R9,-1(R9)	; AND GO THROUGH SAME SEQUENCE
	TLZN	R9,1B31
	JRST	[HRRI	R9,@R9
		JRST	.+2]
	HRR	R9,@R9
	TLZ	R9,^O17
	HLLZM	R9,VIOINS
	MOVEI	R9,(R9)
	CAIGE	R9,^O776000
GOTERR:	JRST	ILLADR
	LSH	R9,2
	ADD	R9,ASOTBL
	HLLI	R9,
	CAMG	R9,ASOTBT
	JRST	ILLADR
	MOVEM	R9,VIOENT
	HRRZ	R9,(R9)
	HRRM	R9,VIOINS
	MOVE	R9,[MOVEM R9,STKSRG+9]
	MOVEM	R9,VIOASO+1
	HLLZ	R9,VIOINS
	TLZ	R9,^O740
	IFN	P$PDP6,
<	CAMN	R9,[SETZM]	; IS IT A FUNNY STORE?
	JRST	VIOOUT	; YES, DO OUTPUT>
	CAMN	R9,[MOVE]	; IS IT A LOAD?
	JRST	VIOINP	; YES, DO INPUT
	CAMN	R9,[SETM]	; IS IT A LOAD W/O INPUT?
	JRST	VIORET+1	; YES, DO LOAD>
	IFN	P$KI10,
<	MOVE	R9,GOTERR	; CHANGE RESPONSE TO ILLEGAL ADDR.
	MOVEM	R9,VIOASO+1	; DURING THIS COMPUTATION
	MOVE	R9,.JBTPC	; GET POINTER TO INSTRUCTION
	ADDI	R9,1	; INCREMENT PC
	HRRM	R9,VIOEXT	; SAVE NEXT INSTRUCTION POINTER
	MOVE	R9,-1(R9)	; GET ACTUAL INSTRUCTION
	TLZN	R9,1B31	; CLOBBER INDIRECT BIT
	JRST	[HRRI	R9,@R9
		JRST	.+2]	; GET IMMEDIATE IF NOT INDIRECT
	HRR	R9,@R9	; GET FIRST LEVEL EFFECTIVE ADDRESS
	TLZ	R9,^O17	; ERASE INDEX FIELD
	HLLZM	R9,VIOINS	; SAVE OP AC,
	MOVEI	R9,(R9)	; CLEAR LH
	CAIGE	R9,^O776000	; IS IT IN LAST 1K OF MEMORY?
GOTERR:	JRST	ILLADR	; NO, ADDRESS ERROR
	LSH	R9,2	; GET -I/O INDEX*4
	ADD	R9,ASOTBL	; + TABLE BASE
	HLLI	R9,	; CLEAR LH
	CAMG	R9,ASOTBT	; LESS THAN TABLE TOP?
	JRST	ILLADR	; YES, ADDRESS ERROR
	MOVEM	R9,VIOENT	; SAVE I/O TABLE ENTRY POINTER
	HRRZ	R9,(R9)	; GET VARIABLE POINTER
	HRRM	R9,VIOINS	; SAVE POINTER
	MOVE	R9,[MOVEM R9,STKSRG+9]	; CHANGE RESPONSE TO ILLEGAL
	MOVEM	R9,VIOASO+1	; ADDRESS BACK TO NORMAL
	HLLZ	R9,VIOINS	; GET OPCODE
	TLZ	R9,^O740
	CAME	R9,[MOVEM]	; IS IT A STORE?
	CAMN	R9,[SETZM]
	JRST	VIOOUT	; YES, DO OUTPUT
	CAMN	R9,[MOVE]	; IS IT A LOAD?
	JRST	VIOINP	; YES, DO INPUT
	CAME	R9,[SETAM]	; IS IT A NON-I/O STORE
	CAMN	R9,[SETM]	; OR LOAD?
	JRST	VIORET+1	; YES, PERFORM ISTRUCTION>
	SOS	VIOEXT	; BUMP POINTER BACK
VIOERA:	UFERR	5,VIOEXT	; NO, ADDRESS ERROR
VIORET:	MOVE	R8,STKSRG+8	; RESTORE R8
	MOVE	R9,STKSRG+9	; RESTORE R9
S$$IOI:			; EXTERNAL NAME FOR INSTRUCTION WORD
VIOINS:	.-.	; PERFORM INSTRUCTION
VIOEXT:	JRST	.-.	; RETURN
ILLADR:	MOVE	R9,[MOVEM R9,STKSRG+9]	; CHANGE RESPONSE TO ILLEGAL
	MOVEM	R9,VIOASO+1	; ADDRESS BACK TO NORMAL
	JRST	VIOERA	; AND TAKE ERROR EXIT
	VARDEF	VIOENT,1	; ASSOCIATION ENTRY POINTER
;  INPUT PROCESSING
VIOINP:	SKIPN	KINP	; IS &INPUT ON?
	JRST	VIORET+1	; NO, DO NOT INPUT
	MOVEM	R8,STKSRG+8	; SAVE R8
	MOVE	R8,VIOENT	; GET ENTRY POINTER
	SKIPN	R9,2(R8)	; GET INPUT WORD, IS IT ZERO?
	JRST	VIORET	; YES, NO INPUT ASSOCIATION
	MOVEM	R7,STKSRG+7	; SAVE R0-R7
	HRRZI	R7,STKSRG
	BLT	R7,STKSRG+6
	HLRZ	R0,3(R8)	; GET MAX INPUT BLOCK SIZE
	JSP	R6,S$$GRS	; GET BLOCK FOR INPUT STRING
	HRLI	R1,^O700	; FORM STRING DESCRIPTOR
	MOVEM	R1,@VIOINS	; SAVE IN VARIABLE LOC
	JRST	(R9)	; PERFORM INPUT

; OUTPUT PROCESSING
VIOOUT:	SKIPN	KOUT	; IS &OUTPUT ON?
	JRST	VIORET+1	; NO, DO NOT OUTPUT
	MOVE	R9,STKSRG+9	; RESTORE R9
	XCT	VIOINS	; DO STORE
	MOVEM	R9,STKSRG+9	; SAVE R9
	MOVEM	R8,STKSRG+8	; SAVE R8
	MOVE	R8,VIOENT	; GET ENTRY POINTER
	SKIPN	R9,1(R8)	; GET OUTPUT WORD, IS IT ZERO?
	JRST	VIORET	; YES, NO OUTPUT ASSOCIATION
	MOVEM	R7,STKSRG+7	; SAVE R0-R7
	HRRZI	R7,STKSRG
	BLT	R7,STKSRG+6
	MOVE	R1,@VIOINS	; GET VALUE DESCRIPTOR
	JSP	R7,S$$CVS	; CONVERT TO STRING FROM ANY TYPE
	JRST	(R9)	; PERFORM OUTPUT
; CONTROLLING TELETYPE LINE MODE INPUT
TTYLMI:	HRRI	R9,0	; START COUNT AT 0
	MOVE	[XWD TLILOP,TLICHR]	; MOVE LOOP INTO R2-R8
	BLT	TLIEND
	JRST	TLICHR	; START LOOP
TLILOP:	PHASE	2
TLICHR:	INCHWL	R0	; R2: GET CHAR
	CAIN	R0,^O15	; R3: IS IT A CARRIAGE RETURN?
	JRST	TLIFIN	; R4: YES, JUMP OUT OF LOOP
	IDPB	R0,R1	; R5: NO, DEPOSIT IN STRING
	AOBJN	R9,TLICHR	; R6: LOOP IF ASSOC LEN IS NOT EXHAUSTED
	MOVE	.-2,.+1	; R7: SET UP TO THROW AWAY REST OF CHARS IN LINE
TLIEND:	JRST	TLICHR	; R8: AND RESUME LOOP
	DEPHASE
TLIFIN:	INCHWL	R0	; THROW AWAY LINE FEED
S$$IIX:			; EXTERNAL NAME FOR INPUT EXIT
VIOIND:	MOVE	R1,@VIOINS	; GET DESCR
	HRRM	R9,(R1)	; SAVE CHARACTER COUNT
	MOVE	R1,MXLN	; ASSURE STRING LENGTH DOES NOT EXCEED &MAXLGTH
	CAIGE	R1,(R9)
	CFERR	15,VIOEXT
	HRLZI	R9,STKSRG	; RESTORE R0-R9
	BLT	R9,R9
	JRST	VIOINS	; EXECUTE INSTRUCTION AND RETURN

; CONTROLLING TELETYPE CHARACTER MODE INPUT
TTYCMI:	HRRZI	R9,1	; ONE CHARACTER
	INCHRW	R0	; GET IT
	IDPB	R0,R1	; PUT IN STRING
	HRRM	R9,-1(R1)	; SET CHAR COUNT
	JRST	VIOIND+2	; FINISH UP INPUT
; CONTROLLING TELETYPE LINE MODE OUTPUT
TTYLMO:	HRRI	R9,0	; START COUNT AT 0
	JUMPE	R1,CRLFTY	; DO CR,LF IF NULL
	HRRZ	R8,(R1)	; GET CHAR COUNT
	JUMPE	R8,CRLFTY	; DO CR,LF IF 0 CHARS
	MOVE	[XWD TLOLOP,TLOCHR]	; MOVE LOOP INTO R2-R6
	BLT	TLOEND
	JRST	TLOCHR	; START LOOP
TLOLOP:	PHASE	2
TLOCHR:	ILDB	R0,R1	; R2: GET CHAR FROM STRING
	OUTCHR	R0	; R3: OUTPUT CHARACTER
	SOJE	R8,CRLFTY	; R4: SKIP OUT IF NO MORE CHARS
	AOBJN	R9,TLOCHR	; R5: LOOP IF ASSOC LEN IS NOT EXHAUSTED
TLOEND:	JRST	ASCLTY	; R6: ASSOC LEN REACHED, SKIP OUT
	DEPHASE
ASCLTY:	OUTCHR	[^O15]	; OUTPUT CR,LF
	OUTCHR	[^O12]
	MOVNI	R9,(R9)	; GET -ASSOC LEN,0 IN R9
	HRLZI	R9,(R9)
	JRST	TLOCHR	; GO BACK TO LOOP
CRLFTY:	OUTCHR	[^O15]	; OUTPUT CR,LF
	OUTCHR	[^O12]
S$$IOX:			; EXTERNAL NAME FOR OUTPUT EXIT
VIOOND:	HRLZI	R9,STKSRG	; RESTORE R0-R9
	BLT	R9,R9
	JRST	@VIOEXT	; EXIT

; CONTROLLING TELETYPE CHARACTER MODE OUTPUT
TTYCMO:	JUMPE	R1,VIOOND	; FINISHED IF NULL
	HRRZ	R8,(R1)	; GET CHAR COUNT
	JUMPE	R8,VIOOND	; FINISHED IF 0 CHARS
	MOVE	[XWD TCOLOP,TCOCHR]	; MOVE LOOP INTO R2-R5
	BLT	TCOEND
	JRST	TCOCHR	; START LOOP
TCOLOP:	PHASE	2
TCOCHR:	ILDB	R0,R1	; R2: GET CHAR FROM STRING
	OUTCHR	R0	; R3: OUTPUT CHAR
	SOJN	R8,TCOCHR	; R4: LOOP FOR EACH CHAR
TCOEND:	JRST	VIOOND	; R5: OR FINISH UP
	DEPHASE
; STORAGE AND INITIAL PARAMETERS
	P$ASIZ=P$ALEN/5	; COMPUTE BLOCK SIZE FOR DEFAULT ASSOCIATION LEN
	IFN	P$ALEN-P$ASIZ*5,<P$ASIZ=P$ASIZ+1>
	P$ASIZ=P$ASIZ+1
S$$AST:			; EXTERNAL NAME FOR POINTER TO TOP OF ASSOC TABLE
ASOTBT:	.+1	; ASSOC TABLE TOP POINTER
	SHD	2,P$ATXT+1,P$ATXT	; ASSOC TABLE HEADER WORD
	REPEAT	P$ATXT-16,<0>	; EMPTY ASSOCIATION ENTRIES
	XWD	S$$OUC,LOCOUC	; 'OUTPUTC' ASSOCIATION
	XWD	0,TTYCMO
	0
	0
	XWD	S$$OUT,LOCOUT	; 'OUTPUT' ASSOCIATION
	XWD	-P$ALEN,TTYLMO
	0
	0
	XWD	S$$INC,LOCINC	; 'INPUTC' ASSOCIATION
	0
	XWD	0,TTYCMI
	XWD	2,0
	XWD	S$$INP,LOCINP	; 'INPUT' ASSOCIATION
	0
	XWD	-P$ALEN,TTYLMI
	XWD	P$ASIZ,0
S$$ASB:			; EXTERNAL NAME FOR POINTER TO BASE OF ASSOC TAB
ASOTBL:	.	; ASSOC TABLE BASE POINTER
	XWD	TTYLMO,TTYLMI	; TTY LINE MODE OUTPUT/INPUT
	XWD	TTYCMO,TTYCMI	; TTY CHAR MODE OUTPUT/INPUT
	SUBTTL	RUNTIME ERRORS

	COMMENT/
CALL:	CFERR	ERRNO,LOC	; CONDITIONALLY FATAL ERROR
CALL:	UFERR	ERRNO,LOC	; UNCONDITIONALLY FATAL ERROR

	STORE ERRNO (ERRNO+16 FOR UFERR) IN &ERRTYPE, AND IF CFERR AND
IF &ERRLIMIT IS NOT 0, DECREMENT &ERRLIMIT AND GO TO FAILPOINT ROUTINE.
OTHERWISE OUTPUT ERROR NUMBER AND LOCATION (C(LOC)-1), AND GO TO SYSTEM
EXIT SEQUENCE/

LCFERR:	MOVEM	R7,SAVXR7	; CONDITIONAL
	JSP	R7,ERRCOM
LUFERR:	MOVEM	R7,SAVXR7	; UNCONDITIONAL
	JSP	R7,ERRCOM
	VARDEF	SAVXR0,8	; SPACE TO SAVE R0-R7
	SAVXR7=SAVXR0+7
ERRCOM:	SUBI	R7,LUFERR	; FORM INDEX (0 OR 2)
	HRRM	R7,ERXTYP	; SAVE
	LDB	R7,[POINT 5,.JBUUO,12]	; GET ERROR TYPE (+16 FOR UFERR)
	MOVEM	R7,ERRT	; SAVE IN &ERRTYPE
ERXTYP:	MOVEI	R7,.-.	; RESTORE INDEX
	JUMPN	R7,.+3	; SKIP OVER IF UNCONDITIONAL
	SOSL	ERLT	; DECREMENT &ERRLIMIT AND
	JRST	S$$FLR	; FAIL IF >0
	HRRZI	R7,SAVXR0	; OTHERWISE SAVE R0-R6
	BLT	R7,SAVXR7-1
	MOVE	R1,ERRPT1	; EDIT ERROR NUMBER
	MOVE	R2,ERRT	; INTO ERROR MESSAGE
	JSP	R4,S$$ITS
	MOVEI	R0,6	; EDIT 6-DIGIT OCTAL ADDRESS
	MOVE	R1,ERRPT2	; INTO ERROR MESSAGE
	MOVE	R2,@.JBUUO	; RH IS ERROR ADDR + 1
	HRLZI	R2,-1(R2)	; LH IS ERROR ADDR
EROCTL:	HLRI	R2,	; CONVERT TO 6-DIGIT OCTAL
	ROT	R2,3
	ADDI	R2,"0"
	IDPB	R2,R1
	SOJN	R0,EROCTL
	MOVE	R1,ERRDSC	; OUTPUT ERROR MESSAGE
	MOVEM	R1,@S$$OUT	; ON 'OUTPUT' DEVICE
	JRST	SYSEXC	; GO TO COMMON EXIT SEQUENCE
; STORAGE
ERRDSC:	POINT	7,.+1,35	; ERROR MESSAGE DESCRIPTOR
	SHD	2,6,23
ERRSTR:	ASCII/ERROR    AT USER       /
ERRPT1:	POINT	7,ERRSTR+1,6	; POINTER TO ERROR TYPE CHARS
ERRPT2:	POINT	7,ERRSTR+3,13	; POINTER TO ERROR LOC CHARS
	SUBTTL	SYSTEM EXITS

	ENTRY	S$$SXT
	EXTERN	S$$TMX,S$$TMF,S$$DMP

	COMMENT/
CALL:	JRST	S$$SXT	; FROM 'END' STATEMENT OF ANY PROGRAM
	DOES OUTPUT OF EXIT MESSAGES, AND TIMING STATISTICS IF REQUIRED.
IF &ABEND IS OFF, AN EXIT 0, IS PERFORMED, OTHERWISE AN EXIT 1, IS DONE/

S$$SXT:	MOVEM	R7,SAVXR7	; SAVE R0-R7
	HRRZI	R7,SAVXR0
	BLT	R7,SAVXR7-1
	MOVE	R1,NORDSC	; OUTPUT NORMAL TERMINATION MESSAGE
	MOVEM	R1,@S$$OUT	; ON 'OUTPUT' DEVICE
SYSEXC:	JSP	R5,S$$TMF	; FINISH TIMING LAST STATEMENT
	SETZ	R0,
	RUNTIM	R0,	; SAVE EXECUTION TIME
	SUB	R0,SSTT	; = FINISH TIME - START TIME
	MOVEM	R0,STATV+4
	MOVE	R1,LOCDC1	; "/IN STATEMENT "
	MOVEM	R1,@S$$OUC
	MOVE	R1,DUMDSC	; OUTPUT STATEMENT NUMBER
	MOVE	R2,STNO
	JSP	R4,S$$ITS
	HRRM	R3,DUMBLK
	MOVE	R1,DUMDSC
	MOVEM	R1,@S$$OUC
	MOVE	R1,LOCDC2	; " OF "
	MOVEM	R1,@S$$OUC
	MOVE	R1,PBLP	; OUTPUT PROGRAM NAME
	MOVE	R1,-2(R1)
	MOVEM	R1,@S$$OUC
	MOVE	R1,LOCDC3	; " AT LEVEL "
	MOVEM	R1,@S$$OUC
	MOVE	R1,DUMDSC	; OUTPUT FUNCTION LEVEL
	MOVE	R2,FNCL
	JSP	R4,S$$ITS
	HRRM	R3,DUMBLK
	MOVE	R1,DUMDSC
	MOVEM	R1,@S$$OUT
	MOVE	R1,STADSC	; "////FASBOL STATISTICS SUMMARY-"
	MOVEM	R1,@S$$OUT
; SET UP DATA FOR STATISTICS LOOP
	MOVE	R1,STATV+4	; GET EXECUTION TIME
	IMULI	R1,1000	; IN MICROSECONDS
	MOVE	R2,STCN	; TOTAL STATEMENTS EXECUTED
	MOVEM	R2,STATV+3
	JUMPE	R2,.+2	; SKIP IF 0
	IDIV	R1,R2	; MICROSEC PER STATEMENT
	MOVEM	R1,STATV
	MOVE	R1,STFC	; GET # OF STATEMENTS FAILED
	MOVEM	R1,STATV+2
	MOVEI	R7,4	; 5 STATISTICS

; STATISTICS LOOP
STATLP:	MOVE	R1,DUMDSC	; CONVERT STATISTIC TO STRING
	MOVE	R2,STATV(R7)
	JSP	R4,S$$ITS
	HRRM	R3,DUMBLK
	MOVEI	R2,INDENT	; LEFT PAD WITH BLANKS
	SUBI	R2,(R3)
	HRRM	R2,BLANKD+1
	MOVE	R1,BLANKD	; OUTPUT PADDING
	MOVEM	R1,@S$$OUC
	MOVE	R1,DUMDSC	; OUTPUT STATISTIC
	MOVEM	R1,@S$$OUC
	MOVE	R1,STATM(R7)	; OUTPUT STATISTIC MESSAGE
	MOVEM	R1,@S$$OUT
	SOJGE	R7,STATLP	; LOOP FOR EACH STATISTIC

; POSSIBLE ADDITIONAL OUTPUT
	MOVE	R6,PRGL	; GET PROGRAM LIST
	JSP	R7,S$$TMX	; PRINT OUT TIMER STATISTICS, IF ANY
	SKIPE	DUMP	; IS &DUMP ON?
	JSP	R7,S$$DMP	; YES, DO DUMP
	HRLZI	R7,SAVXR0	; RESTORE R0-R7
	BLT	R7,R7
	SKIPN	ABND	; IS &ABEND=0?
	EXIT		; YES, EXIT NORMALLY
	EXIT	1,	; NO, EXIT ABNORMALLY
; STORAGE
NORDSC:	POINT	7,.+1,35
	SHD	2,5,18
	ASCII/NORMAL TERMINATION/
LOCDC1:	POINT	7,.+1,35
	SHD	2,4,14
	BYTE	(7)^O12,"I","N"," ","S"
	ASCII/TATEMENT /
DUMDSC:	POINT	7,DUMBLK,35
	VARDEF	DUMBLK,3
LOCDC2:	POINT	7,.+1,35
	SHD	2,2,4
	ASCII/ OF /
LOCDC3:	POINT	7,.+1,35
	SHD	2,3,10
	ASCII/ AT LEVEL /
STADSC:	POINT	7,.+1,35
	SHD	2,7,30
	BYTE	(7)^O12,^O12,^O12,^O12,"F"
	ASCII/ASBOL STATISTICS SUMMARY-/
STATV:	REPEAT	5,<0>	; STATISTICS VARIABLES
	INDENT=15
BLANKD:	POINT	7,.+1,35
	SHD	2,4,15
	ASCII/               /
STATM:	POINT	7,XMSG5,35
	POINT	7,XMSG4,35
	POINT	7,XMSG3,35
	POINT	7,XMSG2,35
	POINT	7,XMSG1,35
XMSG1:	SHD	2,5,19
	ASCII/ MS. EXECUTION TIME/
XMSG2:	SHD	2,5,20
	ASCII/ STATEMENTS EXECUTED/
XMSG3:	SHD	2,5,18
	ASCII/ STATEMENTS FAILED/
XMSG4:	SHD	2,8,33
	ASCII/ REGENERATIONS OF DYNAMIC STORAGE/
XMSG5:	SHD	2,8,32
	ASCII/ MICROSECONDS AVG. PER STATEMENT/
	SUBTTL	SYMBOL TABLE

	ENTRY	S$$SY1,S$$SY2,S$$SYI

	COMMENT"
	SYMBOL LOOKUP
CALL:	JSP	R7,S$$SY1	; WITH TYPE/NO. IN LH(R0), KEY DESCRIPTOR
	IN R1. IF NOT FOUND, RETURN TO 1(R7) WITH TYPE/NO.,MAJOR KEY
	IN R0, KEY DESCR IN R1, PTR TO NEXT LARGER ENTRY IN R2, BUCKET
	POINTER IN R3, AND COMPARE TYPE WORD IN R4. IF FOUND, RETURN
	TO 0(R7) WITH PTR TO VALUE LOC IN R2

	SYMBOL LOOKUP RETRY
CALL:	JSP	R7,S$$SY2	; WITH R0-R4 SET TO RESULTS OF S$$SY1
	(NOT FOUND), EXCEPT TYPE/NO. MODIFIED. SAME RETURN CONVENTIONS
	AS S$$SY1

	SYMBOL BLOCK INITIALIZATION
CALL:	JSP	R10,S$$SYI	; WITH SYMBOL BLOCK POINTER IN R9, SYM-
	BOL TABLE NUMBER IN LH(R8), WITH RH(R8)=0

	SYMBOL ENTRIES ON EACH BUCKET CHAIN ARE ORDERED FROM LEAST TO
GREATEST BY THE TYPE/NO.,MAJOR KEY WORD. THE KEY DESCRIPTOR IS NOR-
MALLY USED AS THE HASHWORD, EXCEPT IN THE CASE OF STRINGS, WHERE THE
HASHWORD IS DERIVED BY ADDING AND SHIFTING FOR EACH CHARACTER UP TO A
MAXIMUM OF 28 CHARACTERS. THE BUCKET ENTRY IS COMPUTED BY DIVIDING THE
HASHWORD BY THE HASHSIZE (=BUCKET TABLE SIZE), USUALLY A PRIME NUMBER.
THE REMAINDER IS USED AS THE BUCKET INDEX RELATIVE TO THE TABLE BASE,
AND THE QUOTIENT TRUNCATED TO THE 18 RIGHTMOST BITS IS USED AS THE
MAJOR KEY"

; SYMBOL BLOCK INITIALIZATION
S$$SYI:	HRL	R9,(R9)	; GET -COUNT INTO LH(R9)
	AOJA	R9,.+2	; POINT AT FIRST ENTRY
SYILOP:	ADDI	R9,3	; 4 WORDS PER ENTRY
	MOVE	R0,1(R9)	; GET TYPE
	MOVE	R1,2(R9)	; GET KEY (STRING) DESCRIPTOR
	TLNE	R0,^O20000	; IS IT TYPE 1,3, OR 5 (LOCAL SYMBOL)
	ADD	R0,R8	; YES, ADD TABLE NUMBER
	JSP	R7,S$$SY1	; LOOK IT UP
	JRST	MLDFER	; SHOULD NOT FIND, ERROR
	HLRZ	R6,(R2)	; SPLICE INTO BUCKET CHAIN
	HRRM	R9,(R6)
	HRLM	R9,(R2)
	HRLI	R2,(R6)
	MOVEM	R2,(R9)
	MOVEM	R0,1(R9)	; SAVE TYPE/NO,MAJOR KEY
	AOBJN	R9,SYILOP	; LOOP
	JRST	(R10)	; RETURN
; SYMBOL LOOKUP AND RETRY
S$$SY1:	MOVE	R2,R1	; GET DESCR
	JUMPE	R2,OTHRTY	; SKIP OUT IF NULL
	TLNE	R2,^O770000	; IS IT STRING?
	JRST	OTHRTY	; NO, SKIP
	HRRZ	R3,(R2)	; GET CHAR COUNT
	CAILE	R3,28	; IS IT >28?
	MOVEI	R3,28	; YES, 28 IS ENOUGH
	SETZ	R4,	; INITIALIZE HASHWORD
	JUMPN	R3,STRNTY	; DO HASH IF CHARS>0
	SETZB	R2,R1	; OTHERWISE SAME AS NULL
OTHRTY:	MOVE	R4,[CAME R1,2(R2)]	; COMPARISON FOR NON- OR NULL STRINGS
	JRST	DOHASH	; GO DO HASH
STRNLP:	LSH	R4,1	; PREPARE FOR ONE MORE CHAR
STRNTY:	ILDB	R5,R2	; GET IT
	ADDI	R4,(R5)	; ADD IT TO HASHWORD
	SOJG	R3,STRNLP	; LOOP FOR N-1 CHARS
	MOVE	R2,R4	; MOVE TO PROPER HASHWORD LOC
	MOVE	R4,[JRST STRCOM]	; COMPARISON FOR STRINGS
DOHASH:	IDIVI	R2,.-.	; DIVIDE BY HASHSIZE (SET BY SYSTEM INI.)
	HRRI	R0,(R2)	; SET MAJOR KEY
	MOVM	R2,R3	; GET BUCKET INDEX
BUCKTB:	ADDI	R2,.-.	; ADD TABLE BASE (SET BY SYSTEM INI.)
	MOVEI	R3,(R2)	; SAVE BUCKET POINTER
	SKIPE	(R2)	; IS BUCKET EMPTY?
	JRST	SRCHLP	; GO SEARCH IF NONZERO
	HRLM	R2,(R2)	; MAKE EMPTY BUCKET CHAIN AND SAVE IN BUCKET
	HRRM	R2,(R2)
	JRST	1(R7)	; RETURN NOT FOUND
SRCHLP:	HRRZ	R2,(R2)	; GET NEXT ENTRY POINTER
S$$SY2:	CAIN	R2,(R3)	; IS IT BUCKET?
	JRST	1(R7)	; YES, RETURN NOT FOUND
	CAMLE	R0,1(R2)	; IS TYPE/NO,MAJOR KEY>ENTRY?
	JRST	SRCHLP	; YES, CONTINUE SEARCH
	CAME	R0,1(R2)	; IS IT EQUAL?
	JRST	1(R7)	; NO, IS <, RETURN NOT FOUND
	XCT	R4	; COMPARE KEYS FOR TRUE EQUALITY
	JRST	SRCHLP	; NOT EQUAL, KEEP SEARCHING
	ADDI	R2,3	; EQUAL, GET PTR TO VALUE WORD
	JRST	(R7)	; AND RETURN FOUND
STRCOM:	HRRZ	R6,(R1)	; GET CRAR COUNT OF KEY
	HRRZ	R5,@2(R2)	; GET CHAR COUNT OF ENTRY KEY
	CAIE	R6,(R5)	; SAME?
	JRST	SRCHLP	; NO, STRINGS CAN'T BE EQUAL
	MOVEM	R1,SYMDSC	; SAVE KEY DESCR
	HRRM	R3,BCKPTR	; SAVE BUCKET POINTER
	MOVE	R4,2(R2)	; GET ENTRY KEY DESCR
COMLOP:	ILDB	R5,R1	; GET CHAR FROM KEY
	ILDB	R3,R4	; GET CHAR FROM ENTRY KEY
	CAIE	R5,(R3)	; SAME?
	JRST	STRNEQ	; NO, STRINGS NOT EQUAL
	SOJG	R6,COMLOP	; LOOP FOR EACH CHAR
	ADDI	R2,3	; OR FINISHED, STRINGS EQUAL,
	JRST	(R7)	; GET PTR TO VALUE WORD AND RETURN FOUND
STRNEQ:	MOVE	R1,SYMDSC	; RESTORE KEY DESCR
BCKPTR:	MOVEI	R3,.-.	; RESTORE BUCKET POINTER
	MOVE	R4,[JRST STRCOM]	; RESTORE EQUALITY TEST
	JRST	SRCHLP	; CONTINUE SEARCHING

; MULTIPLE DEFINITION ERROR
MLDFER:	MOVE	R6,MLDERM
	MOVEM	R6,@S$$OUC
	MOVE	R6,2(R9)
	MOVEM	R6,@S$$OUT
	UFERR	1,PRGLNK
; STORAGE
MLDERM:	POINT	7,.+1,35
	SHD	2,7,30
	ASCII/>>>> MULTIPLY-DEFINED GLOBAL: /
SYMDSC:	BLOCK	1	; DANGEROUS TO USE VARDEF HERE
	SUBTTL	FUNCTION CALL HANDLER

	ENTRY	S$$EQA

	COMMENT/
	EUALIZE ARGUMENTS
CALL:	JSP	R4,S$$EQA	; WITH ACTUAL NUMBER OF ARGS IN R2,
	EXPECTED NUMBER IN R3. ALL ARGUMENTS, IF ANY, ARE ON ES, AND
	EXTRA ONES ARE REMOVED OR NULL VALUES ADDED. R3 IS UNCHANGED

	FUNCTION CALL
CALL:	FCALV	NARG,FLOC	; CALL FOR VALUE
CALL:	FCALN	NARG,FLOC	; CALL FOR NAME
	WHERE NARG IS THE NUMBER OF ACTUAL ARGUMENTS IN THE FUNCTION
	CALL, AND FLOC IS A PTR TO THE FUNCTION WORD. THE LAST ARGUMENT,
	IF ANY, IS IN R1, WITH REMAINING ARGS ON ES.
	THE PC IS SAVED IN PRGLNK, AND IF THE A FIELD OF THE FUNCTION
WORD IS 0, THE NUMBER OF ARGUMENTS SUPPLIED IS EQUALIZED TO THE NUMBER
REQUIRED. THE FUNCTION IS CALLED, WITH APPROPRIATE ACTION TAKEN ON
'RETURN' (JRST (LINK)) AND 'NRETURN' (JRST 1(LINK)), WITH FUNCTION
VALUE RETURNED IN R1. 'FRETURN' WILL CAUSE A DIRECT JUMP TO THE FAILPOINT
ROUTINE/

LFCALN:	JSP	R12,LFCALV+1	; FORM INDEX FOR NAME (0)
LFCALV:	JSP	R12,LFCALV+1	; FORM INDEX FOR VALUE (1)
	SUBI	R12,LFCALV
	MOVE	R2,S$$UPC	; SAVE PC
	MOVEM	R2,PRGLNK
	LDB	R2,[POINT 4,.JBUUO,12]	; GET ACTUAL NUMBER OF ARGS
	JUMPE	R2,.+2	; SKIP IF NO ARGS
	PUSH	ES,R1	; OTHERWISE PUSH LAST ONE ON STACK
	MOVE	R11,@.JBUUO	; GET FUNCTION WORD
	LDB	R3,[POINT 5,R11,12]	; GET 'A' FLAG, REQUIRED ARGS
	TRNN	R3,^O20	; SHOULD ARGS BE EQUALIZED? ('A'=0)
	JSP	R4,S$$EQA	; YES, EQUALIZE THEM
	XCT	FCALL(R12)	; DO FUNCTION CALL
	CFERR	8,PRGLNK	; 'RETURN' FOR NAME CALL, ERROR
	JRST	@PRGLNK	; 'NRETURN' FOR NAME, 'RETURN' FOR VALUE CALL
	MOVE	R1,(R1)	; 'NRETURN' FOR VALUE CALL,
	JRST	@PRGLNK	; GET VALUE FROM NAME
FCALL:	JSP	R12,(R11)	; NAME CALL
	JSP	R12,.+1	; VALUE CALL
	AOJA	R12,(R11)	; RETURNS TO PC 1 GREATER
S$$EQA:	SUBI	R2,(R3)	; GET ACTUAL-DESIRED
	JUMPE	R2,(R4)	; RETURN IF 0
	JUMPL	R2,NULPAD	; DESIRED>ACTUAL, ADD NULL ARGS
	POP	ES,R1	; DESIRED<ACTUAL, GET RID OF EXTRAS
	SOJG	R2,.-1
	JRST	(R4)	; AND RETURN
NULPAD:	SETZ	R1,	; NULL VALUE
	PUSH	ES,R1	; ADD EXTRA ARGS
	AOJL	R2,.-1
	JRST	(R4)	; RETURN
	SUBTTL	DEDICATED MODE ROUTINES

	ENTRY	S$$MKS,S$$MKI,S$$MKR,S$$DSG

	COMMENT/
CALL:	DASGN	TYPE,VLOC	; DEDICATED ASSIGNMENT, WHERE DESCRIPTOR
	IN R1 IS CONVERTED TO APPROPRIATE TYPE (1=STRING, 2=INTEGER,
	3=REAL), AND STORED IN THE VARIABLE LOCATION VLOC

CALL:	JRST	S$$DSG	; LIKE DASGN, EXCEPT VLOC IS ALREADY
	IN R8, AND LINK IN R9 AND IN PRGLNK

CALL:	DCONC	ARGNO,VLOC	; DEDICATED STRING CONCATENATION AND
	ASSIGNMENT, WHERE ARGNO IS THE NUMBER OF ELEMENTS IN THE CON-
	CATENATION (LAST IN R1, REST ON ES), AND VLOC IS THE DEDICATED
	STRING VARIABLE INTO WHICH THE CONCATENATION IS TO BE STORED

CALL:	JSP	R7,S$$MKI	; MAKE INTEGER, WITH DESCRIPTOR IN R1,
	RETURNS TO 0(R7) IF UNABLE, OR TO 1(R7) WITH INTEGER IN R1

CALL:	JSP	R7,S$$MKR	; MAKE REAL, SIMILAR TO S$$MKI

CALL:	JSP	R7,S$$MKS	; MAKE STRING, WITH DESCRIPTOR IN R1.
	RETURNS TO 0(R7) IF UNABLE, OR TO 1(R7) WITH STRING DESCRIPTOR
	IN R1. IF R0<0, THEN IF R1 DOES NOT ALREADY CONTAIN A STRING
	DESCRIPTOR, STORAGE IS ACQUIRED FOR THE NEW STRING, THE DESCRIP-
	TOR FOR THE NEW STRING IS RETURNED IN R1, AND THE CHARACTER
	COUNT FOR THE NEW STRING IS STORED IN THE STORAGE BLOCK. IF R0
	=0 OR >0, THEN THE BYTE POINTER IN R2 IS USED TO STORE THE STRING,
	WITH THE UPDATED BYTE POINTER RETURNED IN R2, THE ORIGINAL BYTE
	POINTER RETURNED IN R1 IF A CONVERSION FROM INTEGER OR REAL WAS
	DONE, AND R0 USED TO DETERMINE THE MAXIMUM CHARACTER COUNT.
	IN ANY CASE, THE ACTUAL CHARACTER COUNT IS RETURNED IN R3/
; DEDICATED ASSIGNMENT
LDASGN:	MOVE	R8,.JBUUO	; GET VLOC POINTER
	MOVE	R9,S$$UPC	; GET LINK
	MOVEM	R9,PRGLNK	; SAVE RETURN LINK
	SKIPN	R3,[POINT 4,R8,12]	; TYPE POINTER FOR LDASGN
S$$DSG:	MOVE	R3,[POINT 2,R8,5]	; TYPE POINTER FOR S$$DSG
	LDB	R2,R3	; GET TYPE
	XCT	CNVDSG-1(R2)	; DO PROPER TYPE OF CONVERSION
	CFERR	1,PRGLNK	; NO CONVERSION POSSIBLE, ILLEGAL TYPE
	MOVEM	R1,(R8)	; STORE INTEGER OR REAL IN LOC
	JRST	(R9)	; RETURN
CNVDSG:	JRST	.+3	; STRING, GO TO CONVERSION SEQUENCE
	JSP	R7,S$$MKI	; INTEGER MAKE
	JSP	R7,S$$MKR	; REAL MAKE
	MOVE	R2,(R8)	; GET BYTE POINTER FO^ DEDICATED STRING
	HLRZ	R0,(R2)	; COMPUTE MAXIMUM CHARACTERS FROM BLOCK SIZE
	SUBI	R0,1
	IMULI	R0,5
	JSP	R7,S$$MKS	; MAKE STRING AND STORE
	CFERR	1,PRGLNK	; COULD NOT BE CONVERTED
	HRRM	R3,@(R8)	; SAVE CHAR COUNT IN STRING
	JRST	(R9)	; RETURN

; DEDICATED STRING CONCATENATION AND ASSIGNMENT
LDCONC:	MOVE	R8,.JBUUO	; GET ARGNO,PTR
	MOVE	R9,S$$UPC	; GET LINK
	MOVEM	R9,PRGLNK	; SAVE LINK
	LDB	R9,[POINT 4,R8,12]	; GET ARGNO
	MOVNI	R9,(R9)	; FORM -(ARGNO,ARGNO)
	HRLI	R9,-1(R9)
	PUSH	ES,R1	; PUSH LAST ELEMENT ONTO ES
	ADD	ES,R9	; RESET ES BELOW ARGS
	HRRI	R9,(ES)	; SET UP ELEMENT POINTER TO FIRST
	AOBJN	R9,.+1
	MOVE	R2,(R8)	; GET BYTE POINTER FOR DEDICATED STRING
	HLRZ	R0,(R2)	; COMPUTE MAX CHARS
	SUBI	R0,1
	IMULI	R0,5
	HRLZI	R8,(R8)	; SAVE LOC PTR, SET INITIAL CHAR COUNT TO 0
DCNLOP:	MOVE	R1,(R9)	; GET NEXT ELEMENT DESCR
	JSP	R7,S$$MKS	; CONV IF NECESSARY, PUT IN DED STRING
	CFERR	1,PRGLNK	; CAN'T CONVERT
	ADDI	R8,(R3)	; INCREASE CHARACTER COUNT
	SUBI	R0,(R3)	; DECREASE MAX CHARS
	AOBJN	R9,DCNLOP	; LOOP FOR EACH ELEMENT
	MOVS	R8,R8	; SWAP LOCPTR,CHARS
	HLRM	R8,@(R8)	; SAVE TOTAL CHARS IN STRING
	JRST	@PRGLNK	; RETURN
; MAKE INTEGER
S$$MKI:	SETZ	R2,	; CLEAR AND SHIFT IN TYPE
	ROTC	R1,2
	XCT	MKITYP(R2)	; EXECUTE ACCORDING TO TYPE
	JRST	1(R7)	; RETURN SUCCESSFULLY
MKITYP:	JRST	S$$STI-1	; STRING, TRY TO MAKE INTEGER
	JRST	(R7)	; NAME, ETC- NO GO
	ASH	R1,-2	; INTEGER
	JSP	R3,S$$RTI	; RESL, CONVERT TO INTEGER

; MAKE REAL
S$$MKR:	SETZ	R2,	; CLEAR AND SHIFT IN TYPE
	ROTC	R1,2
	XCT	MKRTYP(R2)	; EXECUTE ACCORDING TO TYPE
	JRST	1(R7)	; RETURN SUCCESSFULLY
MKRTYP:	JRST	S$$STR-1	; STRING, TRY TO MAKE REAL
	JRST	(R7)	; NAME, ETC- NO GO
	JSP	R3,S$$ITR-1	; INTEGER, SHIFT BACK AND CONVERT
	JRST	1(R7)	; REAL, RETURN

; MAKE STRING
S$$MKS:	JUMPL	R1,MKNSTR	; IF NEG MUST BE INT OR REAL DESCR
	TLNE	R1,^O770000	; IS IT STRING?
	JRST	(R7)	; NO, CAN'T DO
	JUMPN	R1,.+3	; IS IT NULL?
	SETZ	R3,	; YES, SET CHAR COUNT TO 0
	JRST	1(R7)	; AND RETURN
	HRRZ	R3,(R1)	; GET CHAR COUNT
	JUMPL	R0,1(R7)	; IF R0<0, CONVERSION DONE
	JUMPE	R3,1(R7)	; IF CHAR COUNT=0, CONVERSION DONE
	CAIGE	R0,(R3)	; WILL CONVERSION OVERFLOW?
	CFERR	7,PRGLNK	; YES, ERROR
	MOVNI	R3,(R3)	; GET -CHAR COUNT,0 IN R3
	HRLZI	R3,(R3)
	ILDB	R4,R1	; MOVE CHAR FROM DESCR PTR TO BYTE PTR
	IDPB	R4,R2
	AOBJN	R3,.-2	; AND LOOP FOR EACH CHARACTER
	JRST	1(R7)	; RETURN
MKNSTR:	MOVEM	R0,MKSMOD	; SAVE TRANSFER MODE INDICATOR
	JUMPGE	R0,MKNSTC	; STRING STORAGE ALREADY PROVIDED?
	MOVEM	R1,MKSDSC	; NO, SAVE DESCRIPTOR
	MOVEI	R0,4	; GET 12-CHARACTER BLOCK
	JSP	R6,S$$GRS
	MOVEI	R0,12	; 12 CHARS MAX
	MOVE	R2,MKSDSC	; GET DESCRIPTOR BACK
	HRLI	R1,^O700	; FORM STRING DESCRIPTOR
	MOVEM	R1,MKSDSC	; SAVE STRING DESCR
	JRST	.+2
MKNSTC:	EXCH	R1,R2	; SWITCH DESCR,BYTE PTR
	SETZ	R3,	; GET TYPE (2=INT, 3=REAL)
	ROTC	R2,2
	CAIE	R3,3	; IS IT REAL?
	ASH	R2,-2	; NO, FORM INTEGER
	XCT	NTOSTR-2(R3)	; DO APPROPIIATE CONVERSION
	MOVE	R2,MKSDSC	; GET STRING DESCR BACK
	EXCH	R1,R2	; GET UPDATED BYTE PTR INTO R2
	SKIPGE	MKSMOD	; WAS STRING STORAGE PROVIDED?
	HRRM	R3,(R1)	; NO, SAVE CHARACTER COUNT IN STRIN
	JRST	1(R7)	; RETURN
NTOSTR:	JSP	R4,S$$ITS+1	; INTEGER TO STRING
	JSP	R4,S$$RTS+1	; REAL TO STRING
; STORAGE
	VARDEF	MKSMOD,1
	VARDEF	MKSDSC,1
	SUBTTL	DESCRIPTOR MODE CONVERSION

	COMMENT/
CALL:	DICNV	@NLOC	; CONVERT DESCRIPTOR IN @NLOC TO INTEGER, OR IN
	R1 IF @NLOC=0, RETURN VALUE IN R1

CALL:	DRCNV	@NLOC	; CONVERT TO REAL, LIKE DICNV/

LDICNV:	JSP	R7,LDRCNV+1	; INTEGER INDEX=LDRCNV
LDRCNV:	JSP	R7,LDRCNV+1	; REAL INDEX=LDRCNV+1
	MOVE	R6,S$$UPC	; GET LINK
	MOVEM	R6,PRGLNK	; SAVE
	MOVE	R6,.JBUUO	; GET EFF ADR
	TRNE	R6,^O777777	; IS IT ZERO?
	MOVE	R1,(R6)	; NO, GET DESCR, POSSIBLE INPUT
	XCT	DCNVXT-LDRCNV(R7)	; DO CONVERSION
	CFERR	1,PRGLNK	; NOT CONVERTIBLE
	JRST	@PRGLNK	; RETURN
DCNVXT:	JSP	R7,S$$MKI	; MAKE INTEGER
	JSP	R7,S$$MKR	; MAKE REAL
	SUBTTL	ARRAY/TABLE REFERENCE HANDLER

	EXTERN	S$$ARF,S$$TRF

	COMMENT/
CALL:	AREFV	NARG,VLOC	; REFERENCE FOR VALUE
CALL:	AREFN	NARG,VLOC	; REFERENCE FOR NAME
	WHERE NARG IS THE NUMBER OF ARGUMENTS IN THE CALL, AND VLOC IS
THE LOCATION OF THE NAME OF THE VARIABLE HOLDING THE ARRAY OR TABLE
DESCRIPTOR. THE LAST ARGUMENT, IF ANY, IS IN R1, WITH REMAINING ARGS
ON ES. THE PC IS SAVED IN PRGLNK, AND THE NUMBER OF ARGUMENTS SUPPLIED,
PROVIDED THEY DO NOT EXCEED THE NUMBER OF ARGUMENTS EXPECTED,
IS EQUALIZED TO (FOR ARRAYS) THE NUMBER OF DIMENSIONS OR (FOR TABLES) 1.
THE ARRAY OR TABLE REFERENCE ROUTINES ARE CALLED WITH THE DESCRIPTOR IN
R8 AND RETURN A POINTER TO THE ARRAY OR TABLE ELEMENT IN R2. AREFV LOADS
R1 WITH THE CONTENTS OF THE ELEMENT AND RETURNS, AND AREFN FORMS A NAME
DESCRIPTOR FOR THE ELEMENT AND RETURNS/

LAREFV:	JSP	R12,LAREFN+1	; REFERENCE FOR VALUE, INDEX=0
LAREFN:	JSP	R12,LAREFN+1	; REFERENCE FOR NAME, INDEX=1
	SUBI	R12,LAREFN
	MOVE	R2,S$$UPC	; GET LINK
	MOVEM	R2,PRGLNK	; SAVE
	LDB	R2,[POINT 4,.JBUUO,12]	; GET ACTUAL NUMBER OF ARGS
	JUMPE	R2,.+2	; SKIP IF NONE
	PUSH	ES,R1	; OR PUSH LAST ONE ONTO ES
	MOVE	R8,@.JBUUO	; GET NAME OF VAR
	SETM	R8,(R8)	; GET VALUE WITHOUT I/O
	HLLZ	R3,R8	; GET DESCRIPTOR TYPE
	ROT	R3,4
	MOVEI	R5,-5(R3)	; IS IT ARRAY OR TABLE?
	JUMPE	R5,.+2	; YES,SKIP
	CFERR	3,PRGLNK	; NO, ERROR
	JUMPGE	R3,.+3	; JUMP IF ARRAY
	AOS	R3,R5	; OR IF TABLE, SET EXPECTED ARGS=1, TYPE INDEX=1
	JRST	.+3	; AND SKIP
	ROT	R3,9	; GET NUMBER OF ARRAY DIMENSIONS
	ANDI	R3,^O377
	CAILE	R2,(R3)	; IS ACTUAL # OF ARGS > EXPECTED?
	CFERR	3,PRGLNK	; YES, ERROR
	JSP	R4,S$$EQA	; EQUALIZE ARGS
	ADDI	R12,.+2(R12)	; FORM RETURN LINK FOR VALUE OR NAME
	JRST	@ATBREF(R5)	; GO TO ARRAY OR TABLE REF ROUTINE
	MOVE	R1,(R2)	; VALUE CALL, LOAD VALUE
	JRST	@PRGLNK	; AND RETURN TO PROG
	HRLZI	R1,1B19	; NAME CALL, FORM NAME DESCRIPTOR
	ADDI	R1,(R2)
	JRST	@PRGLNK	; AND RETURN TO PROG
ATBREF:	S$$ARF	; ARRAY REF
	S$$TRF	; TABLE REF
	SUBTTL	FAILPOINT ROUTINE

	ENTRY	S$$FLR

	COMMENT/
CALL:	JRST	S$$FLR	; USED FAILPOINT STORED IN FAIL.
	IF LH OF FAIL IS <0, CONTROL IS PASSED TO LOCATION POINTED TO BY
RH OF FAIL (ABNORMAL FAILPOINT, AS IN NEGATION, UNEVALUATED EXPR.).
OTHERWISE ES AND SS ARE RESET TO THEIR PREVIOUS VALUES AND &STFCOUNT
INCREMENTED BEFORE JUMPING TO THE STATEMENT FAILPOINT/

S$$FLR:	MOVE	R1,FAIL	; GET CONTENTS OF FAILPOINT WORD
	JUMPL	R1,(R1)	; GO THERE IF NEGATIVE
	MOVE	ES,ESPR	; OTHERWISE GET PREVIOUS VALUE OF ES (- BASE)
	ADD	ES,ESBA	; (ADD BASE)
	MOVE	SS,SSPR	; AND PREVIOUS VALUE OF SS (- BASE)
	ADD	SS,SSBA	; (ADD BASE)
	AOS	STFC	; INCREMENT &STFCOUNT
	JRST	(R1)	; AND GO TO STATEMENT FAILPOINT
	SUBTTL	UTILITY ROUTINES- INTEGER TO STRING CONVERSION

	ENTRY	S$$ITS

	COMMENT/
CALL:	JSP	R4,S$$ITS	; WITH BYTE POINTER FOR FIRST CHARACTER
	IN R1, INTEGER IN R2, RETURNS UPDATED BYTE POINTER IN R1
AND CHARACTER COUNT IN R3. S$$ITS+1 MAY BE CALLED IF R0 IS ALREADY SET
TO MAXIMUM ALLOWABLE CHARACTER COUNT/

S$$ITS:	MOVEI	R0,12	; NO POSSIBLE STRING OVERFLOW, 11 DIGITS + SIGN
	MOVEM	R4,ITSBLK	; SAVE RETURN LINK FOR EXTRA POPJ
	MOVE	R4,ITSSTK	; GET STACK PTR
	HLRM	R2,NEGSW	; SET SIGN SWITCH
	MOVM	R2,R2	; ASSURE INTEGER IS POSITIVE
DECTOS:	IDIVI	R2,10	; REM IN R3, QUOTIENT IN R2
	HRLM	R3,(R4)	; SAVE REM (NEXT DIGIT)
	JUMPN	R2,DECTO1	; CONTINUE IF ALL DIGITS NOT FORMED
	MOVNI	R3,ITSBLK-1	; COMPUTE NUMBER OF DIGITS
	ADDI	R3,(R4)
	CAIGE	R0,(R3)	; >MAX ALLOWABLE?
	CFERR	7,PRGLNK	; YES, OVERFLOW
	HRRE	R2,NEGSW	; GET SIGN SWITCH
	JUMPGE	R2,DECTO2	; IS IT -?, IF NOT, SKIP
	ADDI	R3,1	; YES, ADD 1 CHAR FOR - SIGN
	CAIGE	R0,(R3)	; >MAX ALLOWABLE
	CFERR	7,PRGLNK	; YES, OVERFLOW
	MOVEI	R2,"-"	; START OFF STRING WITH -
	IDPB	R2,R1
	JRST	DECTO2
DECTO1:	PUSHJ	R4,DECTOS	; COMPUTE MORE DIGITS
DECTO2:	HLRZ	R2,(R4)	; TAKE DIGITS OUT IN OPPOSITE ORDER
	ADDI	R2,"0"	; CONVERT TO ASCII
	IDPB	R2,R1	; AND PUT IN STRING
NEGSW:	POPJ	R4,.-.	; RETURN TO DIGIT LOOP OR CALLING PROGRAM
; STORAGE
ITSSTK:	IOWD	11,ITSBLK+1	; STACK ARTIFICIALLY PUSHED ONCE
	ITSBLK=STKREG	; SPACE FOR STACK
	SUBTTL	UTILITY ROUTINES- REAL TO STRING CONVERSION

	ENTRY	S$$RTS

	COMMENT/
CALL:	JSP	R4,S$$RTS	; WITH REAL IN R2, LIKE S$$ITS/

S$$RTS:	MOVEI	R0,12	; MAX CHARS = 9 SIG DIGITS + SIGN + "." + XTRA 0
	MOVEM	R4,ITSBLK	; SAVE RETURN LINK
	HLRM	R2,NEGSW	; SET SIGN SWITCH
	MOVM	R2,R2	; ASSURE REAL IS POSITIVE
	MULI	R2,^O400	; SEPARATE FRACTION AND EXPONENT
	EXCH	R2,R3	; PUT SHIFTED MANTISSA INTO R2
	HRREI	R4,-^O243(R3)	; AND BINARY POINT SHIFT INTO R4
	JUMPLE	R4,.+2	; ERROR IF >0
	CFERR	9,PRGLNK	; BECAUSE INTEGER > 2**35
	SETZ	R3,	; FORM INTEGER PART IN R2
	ASHC	R2,(R4)
	MOVEM	R3,RFRACT	; SAVE FRACTION
	MOVE	R4,ITSSTK	; GET STACK POINTER
	PUSHJ	R4,DECTOS	; CONVERT INTEGER AND SIGN
	MOVEI	R2,"."	; PUT OUT DECIMAL POINT
	IDPB	R2,R1
	HRLZ	R2,NEGSW	; COMPUTE REMAINING SIGNIFICANCE
	JUMPL	R2,.+2	; -(12-#CHARS) IF "-" SIGN
	ADDI	R2,1	; -(11-#CHARS) IF POSITIVE
	ADDI	R2,(R3)
	HRLZI	R4,-12(R2)	; PUT -REM SIGNIFICANCE IN LH
	HRRI	R4,(R3)	; PUT CHAR COUNT IN RH
	MOVE	R2,RFRACT	; GET FRACTION
FRCTLP:	MULI	R2,10	; NEXT FRACTION DIGIT
	CAIG	R0,(R4)	; <MAX ALLOWABLE CHARS?
	CFERR	7,PRGLNK	; NO, ERROR
	ADDI	R2,"0"	; FORM ASCII DIGIT
	IDPB	R2,R1	; PUT IN STRING
	AOBJP	R4,FRCTND	; SKIP OUT IF SIGNIFICANCE SATISFIED
	MOVE	R2,R3	; RESTORE FRACTION
	JUMPN	R2,FRCTLP	; LOOP IF STILL NONZERO
FRCTND:	MOVEI	R3,(R4)	; GET CHAR COUNT IN R3
	JRST	@ITSBLK	; RETURN
; STORAGE
	VARDEF	RFRACT,1
	SUBTTL	UTILITY ROUTINES- INTEGER TO REAL AND REAL TO INTEGER CONV

	ENTRY	S$$ITR,S$$RTI

	COMMENT/
CALL:	JSP	R3,S$$ITR	; WITH INTEGER IN R1, RETURNS REAL IN R1.
	CALL TO S$$ITR-1 IF R1 CONTAINS INTEGER LEFT SHIFTED 2 BITS

CALL:	JSP	R3,S$$RTI	; WITH REAL IN R1, RETURNS INTEGER IN R1.
	IF MAG(R1)>2**35, ARITHMETIC OVERFLOW OCCURRS/

	ASH	R1,-2	; RESTORE INTEGER FROM TYPE TEST
S$$ITR:	IDIVI	R1,^O400	; DIVIDE INTO TWO PIECES
	SKIPE	R1	; IMPLIES INT < 9 BITS
	TLC	R1,^O243000	; SET EXP TO 243 (27 + 8 DECIMAL)
	TLC	R2,^O233000	; SET EXP TO 233 (27 DECIMAL)
	FAD	R1,R2	; NORMALIZE AND ADD
	JRST	(R3)	; RETURN

S$$RTI:	HLL	R3,R1	; SAVE SIGN IN LINK REG
	MOVM	R1,R1	; ASSURE POSITIVE REAL
	MULI	R1,^O400	; SEPARATE FRACTION AND EXPONENT
	EXCH	R1,R2	; PUT PARTIAL RESULT IN R1
	ASH	R1,-^O243(R2)	; USE EXP AS INDEX TO GET WHOLE PART
	JUMPGE	R3,(R3)	; RETURN IF POSITIVE
	MOVN	R1,R1	; OR COMPLEMENT
	JRST	(R3)	; AND RETURN
	SUBTTL	UTILITY ROUTINES- STRING TO INTEGER OR REAL CONVERSION

	ENTRY	S$$STI,S$$STR,S$$STN

	COMMENT/
CALL:	JSP	R7,S$$STI	; WITH STRING DESRIPTOR IN R1, RETURNS
	TO 0(R7) IF CANNOT BE CONVERTED OR TO 1(R7) WITH INTEGER IN R1.
	CALL TO S$$STI-1 IF DESCRIPTOR NEEDS TO BE SHIFTED BACK

CALL:	JSP	R7,S$$STR	; SAME AS S$$STI EXCEPT RETURNS REAL IN R1

CALL:	JSP	R7,S$$STN	; SAME AS S$$STI EXCEPT RETURNS SUCCESS-
	FULLY TO 2(R7) WITH 2 IN R2 IF VALUE IN R1 IS INTEGER, AND 3 IN
	R2 IF VALUE IN R1 IS REAL

	REAL STRINGS ARE CONVERTED TO INTEGERS AND INTEGER STRINGS TO
REALS IF NECESSARY/

	ROTC	R1,-2	; RESTORE STRING DESCRIPTOR
S$$STN:	MOVEI	R2,2	; START OUT ASSUMING INTEGER
	MOVEM	R2,IRSTMD	; AND SAVE MODE
	JUMPN	R1,S$$STR+2	; PROCESS IF NON-NULL
	JRST	2(R7)	; OR RETURN
	ROTC	R1,-2	; RESTORE STRING DESCR
S$$STI:	JUMPE	R1,1(R7)	; RETURN 0 IF NULL
	SETOM	IRSTMD	; SET MODE TO INT
	JRST	S$$STR+2	; CONTINUE
	ROTC	R1,-2	; RESTORE STRING DESCR
S$$STR:	JUMPE	R1,1(R7)	; RETURN 0 IF NULL
	SETZM	IRSTMD	; SET MODE TO REAL
	HRRZ	R6,(R1)	; GET CHAR COUNT
	JUMPN	R6,.+3	; SKIP IF >0
	SETZ	R1,	; RETURN 0 FOR EMPTY STRING
	JRST	TSTMOD	; RETURN
	SETZ	R3,	; INITIALIZE WHOLE PART
	SETZM	STSIGN	; INITIALIZE SIGN TO +
	ILDB	R2,R1	; GET FIRST CHAR
	CAILE	R2,"-"	; > - SIGN?
	JRST	NOSIGN	; YES, TRY DIGITS
	CAIE	R2,"-"	; IS IT - SIGN?
	JRST	TRYPLS	; NO, TRY +
	SETOM	STSIGN	; YES, SET SIGN TO -
	SOJG	R6,NOSIGN-1	; DECREMENT CHAR COUNT AND CONTINUE
	JRST	(R7)	; OR FAIL IF NO MORE
TRYPLS:	CAIN	R2,"+"	; IS IT + SIGN?
	SOJG	R6,NOSIGN-1	; YES, DECREMENT CHAR COUNT AND CONTINUE
	JRST	(R7)	; NOT + OR NO MORE CHARS, FAIL
	ILDB	R2,R1	; GET NEXT CHAR
NOSIGN:	CAILE	R2,"9"	; >9?
	JRST	(R7)	; YES, FAIL
	SUBI	R2,"0"	; FORM DIGIT
	JUMPL	R2,(R7)	; FAIL IF <"0"
FORMIN:	IMULI	R3,10	; TOT=TOT*10+DIGIT
	ADDI	R3,(R2)
	SOJG	R6,FORMI1	; DECREMENT CHAR COUNT AND CONTINUE
	MOVE	R1,R3	; NO MORE CHARS, GET TOTAL
	SKIPN	R2,IRSTMD	; IS MODE REAL?
	JSP	R3,S$$ITR	; YES, CONVERT TO REAL
INTFIN:	SKIPE	STSIGN	; IS SIGN +?
	MOVN	R1,R1	; NO, NEGATE
TSTMOD:	SKIPG	IRSTMD	; IS MODE OPTIONAL?
	JRST	1(R7)	; NO, RETURN SUCCESSFULLY
	JRST	2(R7)	; YES, RETURN SUCCESSFULLY
FORMI1:	ILDB	R2,R1	; GET NEXT CHAR
	CAILE	R2,"9"	; >"9"?
	JRST	(R7)	; YES, FAIL
	SUBI	R2,"0"	; FORM DIGIT
	JUMPGE	R2,FORMIN	; LOOP IF BETWEEN 0 AND 9
	CAME	R2,["."-"0"]	; OTHERWISE, IS IT "."?
	JRST	(R7)	; NO, FAIL
	MOVEM	R3,WHLPRT	; SAVE WHOLE PART
	SETZ	R3,	; INITIALIZE FRACTION
	MOVNI	R6,(R6)	; FORM -(REM CHARS+1),0
	HRLZI	R6,(R6)
	JRST	.+3	; AND JUMP INTO LOOP
FORMFR:	IMULI	R3,10	; TOT=TOT*10+DIGIT
	ADDI	R3,(R2)
	AOBJN	R6,FORMF1	; SKIP IF ANY CHARS REMAIN
	MOVE	R1,WHLPRT	; OTHERWISE GET WHOLE PART
	SKIPGE	IRSTMD	; IS IT REAL MODE OR OPTIONAL MODE?
	JRST	INTFIN	; NO, GO RETURN INTEGER
	MOVEM	R3,FRCPRT	; SAVE FRACTION PART
	JUMPE	R1,.+2	; SKIP IF WHOLE PART=0
	JSP	R3,S$$ITR	; FORM REAL WHOLE PART
	EXCH	R1,FRCPRT	; EXCHANGE WITH INTEGER FRACTION
	JUMPE	R1,.+3	; SKIP IF FRACT PART=0
	JSP	R3,S$$ITR	; FORM REAL FRACTIONAL PART
	FMP	R1,NEGPWR(R6)	; MULTIPLY BY APPROPRIATE -PWR OF TEN
	FAD	R1,FRCPRT	; ADD WHOLE PART
	SKIPG	R2,IRSTMD	; IS MODE OPTIONAL?
	JRST	INTFIN	; NO, GO CHECK SIGN ON REAL
	AOJA	R2,INTFIN	; YES, GO CHECK SIGN AND RETURN REAL
FORMF1:	ILDB	R2,R1	; GET NEXT CHAR
	CAILE	R2,"9"	; IS IT >"9"
	JRST	(R7)	; YES, FAIL
	SUBI	R2,"0"	; FORM DIGIT
	JUMPGE	R2,FORMFR	; LOOP IF NOT<"0"
	JRST	(R7)	; OR FAIL
; STORAGE
	VARDEF	IRSTMD,1
	VARDEF	STSIGN,1
	VARDEF	WHLPRT,1
	FRCPRT=WHLPRT
	NEGPWR=.-2
	EXP	1.0E-1,1.0E-2,1.0E-3,1.0E-4,1.0E-5,1.0E-6,1.0E-7
	EXP	1.0E-8,1.0E-9,1.0E-10,1.0E-11
	SUBTTL	UTILITY ROUTINES- CONVERT TO STRING ALWAYS

	ENTRY	S$$CVS

	COMMENT/
CALL:	JSP	R7,S$$CVS	; WITH DESCR IN R1, RETURNS STRING IN
	R1. NAMES RETURN 'NAME', ARRAYS 'ARRAY', TABLES 'TABLE', PATTERNS
	'PATTERN', AND PROGRAMMER-DEFINED DATATYPES THEIR NAME/

S$$CVS:	TLNN	R1,^O770000	; IS IT A STRING?
	JRST	(R7)	; YES, RETURN
	JUMPG	R1,CVS1	; JUMP IF NOT INTEGER OR REAL
	SETO	R0,	; OTHERWISE SET UP NUMERICAL TO STRING CONVERSION
	SOJA	R7,MKNSTR	; AND JUMP IN WITH MODIFIED LINK
CVS1:	SETZ	R2,	; GET TYPE BITS
	ROTC	R1,4
	XCT	CVS2-4(R2)	; GET TYPE STRING
	JRST	(R7)	; RETURN
CVS2:	MOVE	R1,CVSNAM	; NAME, GET 'NAME'
	JRST	CVSTAR	; ARRAY OR TABLE
	MOVE	R1,CVSPAT	; PATTERN, GET 'PATTERN'
	JRST	.+1	; DATATYPE
	LSH	R1,-4	; GET DATATYPE NAME
	MOVE	R1,(R1)
	MOVE	R1,(R1)
	JRST	(R7)	; AND RETURN
CVSTAR:	ROTC	R1,1	; GET ARRAY/TABLE BIT
	MOVE	R1,CVSARR-10(R2)	; GET 'ARRAY' OR 'TABLE'
	JRST	(R7)	; RETURN
; STORAGE
CVSNAM:	SDC	2,4,NAME
CVSPAT:	SDC	3,7,PATTERN
CVSARR:	SDC	2,5,ARRAY
	SDC	2,5,TABLE
	SUBTTL	DUMMY FORTRAN ENTRIES

	ENTRY	TYPER.,OVPCWD

	COMMENT/
CALL:	PUSHJ	^017,TYPER.	; WITH ERROR TYPE IN R0

	OVPCWD IS THE PC WORD ON TRAPS/

TYPER.:	CAIE	R0,2	; IS IT 2
	CAIN	R0,5	; OR 5?
	UFERR	14,PRGLNK	; YES, DIVIDE CHECK
	UFERR	15,PRGLNK	; NO, OVERFLOW
OVPCWD:	0
	SUBTTL	LITERALS
	LIT
	END