1
0
mirror of https://github.com/PDP-10/its.git synced 2026-03-07 19:40:48 +00:00
Files
PDP-10.its/src/nlogo/eval.119
Lars Brinkhoff b267d9ff34 SLOGO - PDP-11 Logo for SITS.
This is the very latest version of 11LOGO.  Included in this commit is
a subset of files necessary to assemble 11LOGO for running under SITS.
2022-11-13 15:21:43 -05:00

7648 lines
170 KiB
Plaintext
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
.SBTTL SYSTEM PRIMITIVES
VERSIO
.GLOBL .CRLF,ARGMSK,HOUR,NUMOBS,OPTS,PCHR,SECOND,SOBLST,SSTATS,STIME,VARIAB,YEAR ;001
.OPTIO: MOV #OPTS,A
JSR PC,PRAS
.OPTI1: SEZ
RTS PC
.PRIMI: MOV #SOBLST+2,F
9$: MOV (F)+,B
ADD #SOBLST,B
BIT #VARIAB*400,(B)
BEQ 1$
PRTXT <(>
1$: MOV B,A
CMP (A)+,(A)+
JSR PC,PRAS
MOV #'A,D
MOVB 1(B),C
BIC #ARGMSK,C
BEQ 3$
2$: PRTXT < :>
JSR PC,@PCHR
INC D
SOB C,2$
3$: BIT #VARIAB*400,(B)
BEQ 4$
PRTXT <)>
4$: JSR PC,.CRLF
CMP F,#SOBLST+<NUMOBS*2>
BLO 9$
SEZ
RTS PC
.IFNZ ENG&FR
ENGLIS:
ANGLAI: MOV #ENGFLG,LANG
ENG1: SEZ
RTS PC
FRENCH:
FRANCAIS: MOV #PFRFLG!FRFLG,LANG
BR ENG1
FRANGLAIS: BIS #ENGFLG!FRFLG,LANG
BR ENG1
.ENDC
.GLOBL WTA,S,TOPS,UDA,WTAB ;003
;THIS IS THE STUFF FOR ARRAY HACKING
AMAKE: ASL D
ADD S,D
MOV -(D),A ;ADDR OF ARRAY NAME
AMAKE5: MOV A,B
BIC #7777,A
CMP #ATOM,A ;IS A TYPE ATOM?
BNE AMAKE3 ;NO
AMAKE4: MOV #ABIND,A
JSR PC,.BINDL
BEQ AMAKE6
JMP CLRTOP
AMAKE3: CMP #LSTR,A ;IS A TYPE LSTR?
BNE AMAKE2 ;YES
BIT #7777,B ;NULL POIMTER?
BEQ AMAKE2 ;YES
MOV B,TOPS
JSR PC,UOBSCH ;GET ATOM
BNE AMAKE4
AMAKE6: ERROR+UDA
AMAKE2: ERROR+WTAB
.GLOBL HEADER ;004
.GLOBL ROB,WNA ;004
ARRAD: MOV B,E
SPUSH E ;TOP OF ARRAY HEADER
CMPB 4(E),F ;IS DIM=NO. OF INDICES?
BEQ ARRAD1 ;YES
ERROR+WNA ;WRONG NO OF ARGS
ARRAD1: CLR A ;TEMP ACCUMULATOR
ADD #12,E ;LENGTH OF DIMENSION IN E
ARRAD2: JSR PC,G1NARG ;GET INDEX OFF S-PDL
CMP B,(E) ;INDEX IN BOUNDS?
BGE ARRAD4 ;NO
TST B ;NEGATIVE INDEX?
BGE .+4 ;INDEX OK
ARRAD4: ERROR+ROB
ADD B,A
DEC F
BEQ ARRAD3 ;MORE INPUT
MUL -(E),A
MOV B,A
BR ARRAD2
ARRAD3: SPOP E ;ADDR OF ARRAY HEADER
TSTB 5(E) ;IS TYPE PTR?
BEQ 1$
ASL A
1$: ASL A ;TOTAL OFFSET (A*4)
ADD #HEADER,A ;ADDR OF FIRST VALUE
ADD E,A ;ADDR OF VALUE TO BE STORED
RTS PC
STORE: SAVE D
JSR PC,AMAKE
SPOP F ;NO. OF ARGUMENTS
SUB #2,F
POPS D ;VALUE TO BE STORED
JSR PC,ARRAD ;FIND STORAGE LOCATION
MOV A,F
MOV 4(E),A
MOV D,B
BIC #7777,A
BEQ STORE1
JSR PC,CONVERT
BNE 1$
ERROR+WTAB
1$: JSR PC,.LOADB
MOV A,(F)+
STORE1: MOV B,(F) ;VALUE IS NOW STORED
ADD #2,S
SRTSPC: SEZ
RTS PC
GET: SAVE D
JSR PC,AMAKE
SPOP F ;NO. OF ARGUMENTS
DEC F ;NO. OF INDICES
JSR PC,ARRAD ;COMPUTE STORAGE LOCATION
MOV A,F ;STORAGE LOCATION ADDR IN F
MOV (F),C
TSTB 5(E) ;TEST TYPE
BEQ GET1 ;TYPE 0 (PTR)
MOV (F)+,A
MOV (F),B
JSR PC,GRBAD ;STORES VALUE IN NODE SPACE
MOV 4(E),D
BIC #7777,D
BIS D,C ;SET TYPE ON PTR TO VALUE
GET1: MOV C,@S ;PTR ON TOP OF S-PDL
CLZ
RTS PC
;DEFINE AN ARRAY
.GLOBL ERW,LIMIT,WDIM,BAT,ASPACE,ARTOP,NAS,.RELES,..ALLO,TMPBLK
DEFAR: MOV D,F
CMP F,#LIMIT+2 ;WHICH SHOULD BE < ALLOWABLE LIMIT
BLE OKARAY ;OKAY,THIS IS.
AERROR: ERROR+WDIM
OKARAY: SUB #2,F ;DIMENSION OF ARRAY IN F
MOV F,A
MOV #1,D ;SET UP FOR MULTIPLICATION
JSR PC,G1NARG ;GET TYPE
MOV B,E ;SAVE IT
BEQ ALNUM ;0 FOR LNUM
.IFNZ FPPF
CMP #1,B
BEQ AFNUM ;1 FOR FNUM
.ENDC
CMP #2,B
BEQ NXTIDX ;2 FOR PTR
ERROR+BAT
ALNUM: BIS #LNUM,F
BR NXTIDX
.IFNZ FPPF
AFNUM: BIS #FNUM,F
.ENDC
NXTIDX: JSR PC,G1NARG ;GET MAGNITUDE OF LAST DIMENSION
PUSH B ;SAVE THIS DIMENSION
MUL B,D ;D IS ODD
BLE AERROR ;DIMENSION < 0
BCS AERROR ;DIMENSION TOO BIG
SOB A,NXTIDX
SPUSH F ;SAVE DIMENSION OF ARRAY
BIT #160000,D ;SIZE SHOULD NOT BE TOO BIG
BNE AERROR
CMP #2,E ;IS THIS PTR ARRAY
BEQ WALLOC
ASL D ;THIS IS DOUBLE PRECISION ARRAY
WALLOC: ASL D ;TO CONVERT TO BYTES
ADD #HEADER,D
SPUSH D ;SAVE SIZE OF ARRAY BLOCK
MOV @S,B ;GET NAME OF ARRAY
MOV B,A
BIC #7777,A ;SEE WHETHER IT HAS BEEN INTERNED?
CMP #ATOM,A ;BY TESTING ITS TYPE
BEQ FABIND ;YES
CMP #LSTR,A ;NO,IS NAME ALL RIGHT
BEQ 1$ ;YES
ERROR+WTAB
1$: MOV B,TOPS
JSR PC,UINTRN ;INTERN NAME OF ARRAY
MOV B,@S ;SAVE UOE PTR
FABIND: CLR TOPS ;NOT TO CHANGE BINDING
MOV #ABIND,A ;SEE IF AN ARRAY IS
JSR PC,.BIND ;BINDED TO THIS NAME
BEQ GETSPA ;NO
MOV C,@S ;SAVE PTR TO BINDING NODE
MOV B,C
MOV 2(C),B
ADD ASPACE,B ;ADDED TO AVAILABLE FREE SPACE
.IF NZ SITS
ADD #<ARYHPG-ARYPG+1>_13.+ARYAD,B ;TOTAL POSSIBLE ARRAY SPACE
SUB ARTOP,B ;AMOUNT OF CORE GOTTEN SO FAR
.ENDC
CMP B,(P) ;IS SUM ENOUGH FOR NEW BINDING?
BGE ERAOLD ;YES
FULL: ERROR+NAS ;NOT ENOUGH SPACE
ERAOLD: MOV C,B
JSR PC,.RELES ;RELEASE OLD BINDING
;FALLS THROUGH
;FALLS IN
GETSPA: SPOP B ;GET SIZE OF ARRAY
MOV B,D ;SAVE IT
JSR PC,..ALLOC ;ASSIGN SPACE
BEQ FULL ;NOT ENOUGH
SPOPS B ;UOE PTR
SPUSH A ;PUSH IT ON THE P PDL
MOV P,(A) ;MAKE THE ARRAY POINT BACK TO THE PDL SLOT
MOV #ABIND,A
MOV #LSTR,TOPS ;HAVE TO BIND IT TO SOMETHING
JSR PC,.BIND ;BIND NEW ARRAY
BIC #170000,C ;PTR TO BINDING NODE
ASL C
ASL C
ADD #NODESP+2,C ;THIS IS PHYSICAL ADDR OF BINDING NODE
SPOP A ;GET BACK POINTER TO THE ARRAY
MOV A,TMPBLK ;FOR MAKEWINDOW
MOV A,(C) ;MAKE THE BINDING NODE POINT TO THE ARRAY
MOV C,(A)+ ;BACK PTR FIRST ENTRY IN HEADER
MOV (A)+,D ;SIZE OF ARAY SECOND
SPOP F
MOV F,(A)+ ;DIMENSION OF ARRAY THIRD
ADD #LIMIT*2,A ;TO ADVANCE (A)
BIC #177400,F ;GET DIMENSION PART
MOV F,E
ASL E ;TO GET IT INTO BYTES
SUB E,A ;FOR OFFSET INTO HEADER
1$: SPOP (A)+
SOB F,1$
MOV (C),A
CLR C ;FOR CLEARING THE ARRAY
BIT #170000,4(A) ;IS IT A POINTER ARRAY?
BNE 2$ ;NO
MOV #LIST,C ;FILL IT WITH EMPTY LISTS
2$: ADD #HEADER,A
SUB #HEADER,D
ASR D
3$: MOV C,(A)+ ;ZERO ARRAY VALUES
SOB D,3$
JMP CLRTOP
.GLOBL RTB ;014
ERARAY: JSR PC,GTUOEB ;GET NEXT TOKEN
BNE ERARA1
ERARA2: CLR TOPS
MOV #ABIND,A
MOV B,F
JSR PC,.BIND
BEQ ERARAR
JSR PC,.RELES ;RELEASE ARRAY BLOCK
MOV F,B
JSR PC,.UNBND
ERARAR: SEZ
RTS PC
ERARA1: CMP #UFUN,A
BGT 1$
ERROR+ERW
1$: JSR PC,CVSFLS
MOV #ATOM,A
JSR PC,.OBSCH
BNE ERARA2
RTS PC
ERARAS: JSR PC,GNOLEI
ERARS1: JSR PC,GNOLE
BEQ ERARAR
MOV B,F
CLR TOPS
MOV #ABIND,A
JSR PC,.BIND
BEQ ERARS1 ;THIS NAME HAS NO ARRAY BINDING
JSR PC,.RELES ;RELEASE THIS ARRAYY
MOV F,B
JSR PC,.UNBND
BR ERARS1
;RETURNS SIZE OF ARRAY DIMENSIONS
ASIZEX: POPS A ;GET THE ARRAY NAME
JSR PC,AMAKE5 ;FINDS THE START OF THE ARRAY
ASIZE2: PUSH E
MOV B,E
MOVB 4(E),D ;TYPE/DIM WORD
MOV D,F
SPUSH D ;SAVE IT
ASL D ;SETS UP OFFSET FOR DIMENSION WORD
SUB D,E
ADD #14,E ;ADDR. OF FIRST DIM.
ASIZE1: MOV (E)+,B
JSR PC,.CSNIN ;CONVERT TO INUM AND PUT IN NODE
SPUSHS C ;SAVE PTR ON S-PDL
SOB F,ASIZE1 ;CHECK FO MORE DIMS.
SPOP D ;NO OF DIMS. IN D
JSR PC,SENT. ;LINK DIMS. IN LIST
POP E
CLZ
RTS PC
.SBTTL ARITHMETIC ROUTINES
.IFNZ FPPF
;FLOATING POINT MACROS
.MACRO FPUSH FF
STF FF,-(P)
JSR PC,PPUSHT
.ENDM
.MACRO FPOP FF
LDD (P)+,FF
JSR PC,PPOPT
.ENDM
.ENDC
.IFZ FPPF
;SINGLE PRECISION ARITHMETIC ROUTINES
UPLUS: CLZ ;UNARY PLUS - NOTHING TO DO
RTS PC
UMINS: JSR PC,G1IARG ;UNARY MINUS
DPNEG B,C
DONBC: JMP R1I.BC
SUM:
CLR E
CLR F
TST D
BLE DIFF.2 ;DONE
SUM.1: JSR PC,G1IARG ;GET 1 INTEGER
DPADD B,C,E,F
DEC D ;COUNTER
BGT SUM.1
BR DIFF.2 ;DONE
DIFF:
JSR PC,G2IARG ;GET 2 INTEGERS
DPSUB B,C,E,F
DIFF.2: CMP E,#100000 ;IS ANSWER = 100...00 ?
BNE DONEMP
TST F ;IF SO , THEN ERROR
BNE DONEMP
ERROR+RTB ;SINCE THAT IS SMALLEST NEG NUMBER
DONEMP: JMP R1I.EF
PROD:
CLR E
MOV #1,F
PROD.1: DEC D
BLT DONEMP ;DONE
JSR PC,G1IARG ;GET ONE ARG IN B
JSR PC,.DPMUL
BNE PROD.1
ERROR+RTB ;RESULT TOO BIG
MOD:
JSR PC,G2IARG
JSR PC,.DPDIV
BNE DONBC
ERROR+RTB
DIVDE:
DIV.1: JSR PC,G2IARG
JSR PC,.DPDIV
BNE DONEMP
ERROR+RTB
.ENDC
.IFNZ FPPF
;FLOATING POINT ARITHMETIC ROUTINES
ERRET: ERROR+RTB
UPLUS: CLZ
RTS PC
UMINS: MOV #INUM,F
JSR PC,G1ARG
LDD FA,FB
NEGF FB
BR .FSTOR ;STORE FB
DIFF: JSR PC,G2ARG ;LOAD FA AND FB
SUBF FA,FB
CFCC
BVS ERRET ;OVERFLOW?
BR .FSTOR ;STORE IT
SUM: MOV #INUM,F
CLRF FB
TST D
BLE .FSTOR
SUM.1: JSR PC,G1ARG ;GET A NUMBER
ADDF FA,FB
CFCC
BVS ERRET ;OVERFLOW?
DEC D
BGT SUM.1 ;ADD MORE NUMBERS
BR .FSTOR ;DONE AT LAST
PROD: MOV #INUM,F
LDCFD #40200,FB ;LOAD CONSTANT "1"
TST D
BLE .FSTOR ;DONE ALREADY
PROD.1: JSR PC,G1ARG
MULF FA,FB
CFCC
BVS ERRET ;OVERFLOW?
DEC D
BGT PROD.1 ;LOOK AT COUNTER
;FALLS THROUGH
;FALLS IN
;THIS TAKES A NUMBER OUT OF FB AND
;CONVERTS IT ACCORDING TO TYPE IN REG F (INUM,FNUM)
;AND RETURNS
.FSTOR: CMP #FNUM,F ;FNUM OR INUM?
BEQ .FST.2
STCFI FB,-(P) ;PUT INUM ON STACK
BCS ERRET ;OVERFLOW?
.FST.1: SPOP A
SPOP B
JSR PC,GRBAD ;STORE ANSWER
BIS F,C ;SET TYPE
JMP ORTC
.FST.2: STCDF FB,-(P) ;PUT FNUM ON STACK
JMP .FST.1
DIVDE: JSR PC,G2ARG ;GET ARGS
TSTF FA ;TEST ZERO DIVIDE
CFCC
BEQ ERRET ;IT WAS!!??
DIVF FA,FB
CFCC
BVS ERRET ;OVERFLOW?
BR .FSTOR ;STORE IT
MOD: JSR PC,G2ARG ;GET ARGUMENTS IN FA AND FB
SPUSH #.FSTOR
.MOD: TSTF FA ;IS FA 0?
CFCC
BEQ ERRET ;IT IS??
LDD FB,FC ;FC <- FB
DIVF FA,FC ;FC <- (FB/FA)
CFCC
BVS MOD2 ;THE ANSWER IS 0
MODD #40200,FC ;SEPERATE INTEGER AND FRACTION PARTS
MULF FA,FD ;FD <- FA * (INT (FB/FA))
SUBF FD,FB ;FB <- MOD (FB,FA)
MOD1: CFCC
BGE MOD3 ;IS IT POSITIVE?
ADDF FA,FB ;NO, ADD FA
BR MOD1
MOD2: CLRF FB
MOD3: RTS PC
.GLOBL GCPREV ;016
SQRT: MOV @S,GCPREV ;SAVE THIS WORD
JSR PC,G1NUM
BNE SQRT2
SQRT1: MOV GCPREV,B ;GET POINTER TO NUMBER OR ARGUMENT
ERROR+WTAB
SQRT2: TSTF FA
CFCC
BMI SQRT1
BEQ SQRTRT
CLR GCPREV ;NO NEED FOR THIS ANYMORE.
LDF FA,FB
STEXP FA,A
LDEXP #0,FA
ASR A
ADC A
ADDF #40000,FA
BCS 1$
ADDF #40000,FA
1$: CLRF FC
LDEXP A,FC
MULF FC,FA
MOV #4,A
SQRTLP: LDF FB,FC ;FC <= X
DIVF FA,FC ;FC <= X/Y
ADDF FC,FA ;FA <= Y + X/Y
MULF #40000,FA ;FA <= 1/2 * (Y + X/Y)
SOB A,SQRTLP
SQRTRT: MOV #FNUM,F
STCDF FA,-(P)
JMP .FST.1
; CALL WITH D POINTING TO CURX OR CURY.
; RETURN THE INTEGER OF CURX OR CURY IN B
GETINT: MOV (D)+,B ;THE FRACTION PART
ROL B
MOV (D)+,B ;THE INTEGER PART
ADC B ;ROUND
RTS PC
.GLOBL PI ;019
.GLOBL ACOPI,ATANTB,PITWO,TMNI ;020
SINEF: MOV #SINDEG,E
SINEF1: JSR PC,G1NUM ;FA <- ARGUMENT
BNE 1$
ERROR+WTAB ;WRONG TYPE OF ARG
1$: JSR PC,(E) ;FA <- SINE (FA)
COSF1: MOV #FNUM,F ;TELL .FST.1 IT'S AN FNUM
STCDF FA,-(P) ;PUT SINE ON STACK FOR .FST.1
JMP .FST.1 ;PUT IT INTO A NODE
COSF: MOV #COSDEG,E
BR SINEF1
SINDEG: MOV #-1,A
BR TRIG
COSDEG: MOV #1,A
TRIG: MOV #1,B
TSTF FA
CFCC
BGE TRIG1
NEGF FA
MUL A,B
TRIG1: DIVF #41464,FA ;DIVIDE BY 45
MODD #40200,FA ;SEPERATE FRACTION AND INTEGER
MODD #37400,FB
MULF #41000,FB ;MOD 8
SETI
STCFI FB,C
SETL
ASL C
ADD C,PC
BR .TRIG0
BR .TRIG1
BR .TRIG2
BR .TRIG3
BR .TRIG4
BR .TRIG5
BR .TRIG6
MUL A,B
BR .TRIG7
.TRIG6: MUL A,B
NEG A
BR .TRIG0
.TRIG4: NEG B
BR .TRIG0
.TRIG3: NEG B
MUL A,B
BR .TRIG7
.TRIG2: NEG A
MUL A,B
BR .TRIG0
.TRIG5: NEG B
.TRIG1: NEG A
.TRIG7: SUBF #40200,FA ;WE WANT 45 - ANGLE
NEGF FA
;FALLS THROUGH
;FALLS IN
.TRIG0: MULF PI,FA
MULF #37600,FA ;CONVERT FROM DEGREES TO RADIANS
LDD FA,FD
MULF FD,FD
NEGF FD ;-ANGLE SQUARED INTO FD
LDCFD #40200,FB ;COUNTING CONSTANT "1"
STF FB,FF
TST A
BLT .TRIG9 ;WE WANT SIN
LDD FB,FA
CLRF FB
.TRIG9: LDD FA,FC
TSTF FD
CFCC
BEQ TRIG11
TRIG10: ADDF FF,FB
DIVF FB,FC
ADDF FF,FB
DIVF FB,FC
MULF FD,FC
ADDF FC,FA
CMPF #41100,FB
CFCC
BGE TRIG10
TRIG11: TST B
BGE 1$
NEGF FA
1$: RTS PC
;ARCTAN ROUTINE
;ARG RECEIVED & RETURNED IN FA
;CALL ARG "X"; IT KEEPS CHANGING AS IT PASSES THRU THESE ROUTINES
ATAN: JSR PC,G1ARG ;ARG IN FA, DOES SEZ IF IT FINDS A NUMBER
BNE 2$ ;DID WE GET A NUMBER?
ERROR+WTA ;NO
2$: SETD ;DOUBLE PRECISION
;IF X >= 0, ATAN(X) = 180/PI * ATAN1(X)
;IF X < 0, ATAN(X) = -180/PI * ATAN1(-X)
LDD ACOPI,FD ;FD = 180/PI
STD FD,FE ;SAVE IT IN FE
TSTD FA ;X >= 0?
CFCC
BGE 1$ ;IF SO, BRANCH
NEGD FA ;FA = -X
NEGD FE ;FE = -180/PI
1$: JSR PC,ATAN1
MULD FE,FA ;RESULT IN FA
JMP COSF1 ;RETURN ARG
;IF X < 10**-9, ATAN1(X) = X
;IF X > 1, ATAN1(X) = PI/2 - ATAN2(1/X)
;ELSE ATAN1(X) = ATAN2(X)
ATAN1: CMPD TMNI,FA ;IS 10**-9 > X?
CFCC
BGT ATAN1B ;YES, X SMALL SO OUTPUT X
CMPD #40200,FA ;1 < X?
CFCC
BGE ATAN2 ;YES, SO OUTPUT ATAN2(X)
LDD #40200,FB ;LOAD A 1 INTO FB
DIVD FA,FB ;FB = 1/X
LDD FB,FA ;TRANSFER TO FA
JSR PC,ATAN2 ;ATAN2(1/X)
LDD PITWO,FB ;FB = PI/2
SUBD FA,FB ;FB = PI/2 - ATAN2(1/X)
LDD FB,FA ;TRANSFER TO FA
ATAN1B: RTS PC
;ATAN2(X) = (X*(B0+(A1/(Z+B1+(A2/(Z+B2+(A3/(Z+B3))))))))
;WHERE Z = X**2
;INTERMEDIATE RESULT CALLED "OP"
ATAN2: LDD FA,FB ;FA CONTAINS X
MULD FB,FB ;FB = X**2
MOV #ATANTB,D ;POINT TO TABLE OF CONSTANTS
LDD FB,FC ;FC = Z
ADDD (D)+,FC ;FC = B3 + Z
LDD (D)+,FD ;FD = A3
DIVD FC,FD ;FD = A3/OP; FD = NEW OP
LDD (D)+,FC ;FC = B2
ADDD FB,FC ;FC = Z + B2
ADDD FD,FC ;FC = FC + OP; FC = NEW OP
LDD (D)+,FD ;FD = A2
DIVD FC,FD ;FD = A2/OP; FD = NEW OP
ADDD (D)+,FB ;FB = Z +B1
ADDD FD,FB ;FB = FB + OP; FB = NEW OP
LDD (D)+,FD ;FD = A1
DIVD FB,FD ;FD = A1/OP; FD = NEW OP
ADDD (D)+,FD ;FD = OP + B0
MULD FD,FA ;FA = OP * X
RTS PC
.ENDC
.GLOBL NUM1,NUM1E,NUM2,NUM2E ;021
.IFNZ SARITH
;STRING PLUS JUST ADDS ITS TWO NUMBERS BY LINEARIZING THEM INTO NUM1 AND NUM2
;IT THEN ADDS THEM IN 9'S COMPLEMENT, RECONVERTING THE NUMBER IF NEEDED.
STNGPL: JSR PC,LIN2AR ;LINEARIZE THE TWO ARGS INTO NUM1 AND NUM2
;ALSO SET UP NUM1E AND NUM2E
;THIS ENTRY ALSO USED BY STRING MINUS
STNGAD: MOV NUM1E,B ;GET THE NUMBER OF DIGITS TO ADD TOGETHER
SUB #NUM1,B ;TURN IT INTO THE LENGTH
CLR C ;NO CARRY
ADDLOP: DEC B ;DEC POINTER
MOVB NUM1(B),D ;GET THE FIRST DIGIT
MOVB NUM2(B),E ;GET SECOND DIGIT
ADD D,E ;GET SUM
ADD C,E ;ADD IN THE CARRY
CLR C ;CLEAR THE CARRY FOR NEXT TIME
CMP E,#10. ;IS IT TOO BIG
BLO 1$ ;NO, JUST GO AHEAD
INC C ;SET CARRY
SUB #10.,E ;AND MAKE IT SMALL AGAIN
1$: MOVB E,NUM2(B) ;AND PUT IT BACK IN THE LIST
TST B ;ARE WE DONE YET?
BNE ADDLOP ;NOPE, CONTINUE
2$: CLR C ;THE SIGN IS POSITIVE
TSTB NUM2 ;IS THE RESULT NEGATIVE?
BEQ 3$ ;NO, IGNORE THIS
MOV NUM2E,B ;END IN B
MOV B,A ;COPY IT
SUB #NUM2,A ;GET POINTER TO THE NUMBER
JSR PC,COMPL ;COMPLEMENT IT
MOV #1,C ;SET NEGATIVE FLAG
3$: MOV #NUM2,A ;GET POINTER TO THE NUMBER
MOV NUM2E,B ;GET END OF NUMBER TO MAKE
;;; FALLS IN TO RETURN A STRING NUMBER
;;; A POINTS TO THE NUMBER, B THE END, AND C THE SIGN
RETSNG: JSR PC,BLSTI ;MAKE A LIST
TST C ;IS THE RESULT NEGATIVE?
BEQ 1$ ;NO, DO NOTHING
MOV #'-,D ;PUT A MINUS SIGN IN FRONT
JSR PC,BLST
1$: CMP A,B ;ARE WE AT THE END?
BEQ 2$ ;YES, JUST PRETEND WE HAVE FOUND NON ZERO BYTE
TSTB (A)+ ;IS IT 0?
BEQ 1$ ;YES, JUST CONTINUE
2$: TSTB -(A) ;BACK UP TO THE NON-ZERO WORD
3$: MOVB (A)+,D ;GET THE NUMBER
ADD #'0,D ;CONVERT IT TO ASCII
JSR PC,BLST ;AND BUILD IT ONTO THE LIST
CMP B,A ;IS IT AT THE START OF NUMBER?
BNE 3$ ;NO, GO BACK FOR NEXT DIGIT
JSR PC,BLSTF ;GET POINTER TO STRING IN TOPS
PUSHS TOPS ;PUSH IT ON THE OUTPUT PDL
CLR TOPS
CLZ
RTS PC ;WE ARE RETURNING A NUMBER STRING
STNGMI: JSR PC,LIN2AR ;LINEARIZE THE ARGS AND RETURN THE LENGTH IN A
MOV NUM1E,B ;POINTER TO THE END OF NUM1
JSR PC,COMPL ;COMPLEMENT IT
BR STNGAD ;NOW PRETEND IT IS AN ADD
;LINEARIZE TWO ARGS OFF THE S PDL
LIN2AR: MOV #NUM1,A ;POINTER TO THE FIRST AREA
JSR PC,LINEAR ;LINEARIZE THE NUMBER INTO NUM1
MOV A,NUM1E ;THE END OF THE FIRST NUMBER
SPUSH B ;SAVE THE SIGN
MOV #NUM2,A ;AND THE SECOND AREA
JSR PC,LINEAR ;DO THE SAME FOR THE SECOND NUMBER
MOV A,NUM2E
SPUSH B ;SAVE THE SIGN AGAIN
MOV A,B ;COPY POINTER TO NUM2E
SUB NUM1E,B ;GET THE DIFFERENCE IN LENGTHS
SUB #NUM2-NUM1,B ;SUBTRACT OFFSET
BEQ SINCAL ;NO DIFFERENCE, JUST DO SIGNS
BPL 1$ ;(NUM2 IS LONGER THAN NUM1)
NEG B ;MAKE IT POSITIVE (NUM1 IS LONGER THAN NUM2 HERE)
MOV #NUM2,D ;POINTER TO THE START OF THE NUMBER
ADD B,NUM2E
BR 2$ ;BLT UP NUM2 POINTER IN A
1$: MOV NUM1E,A ;POINTER TO NUM1 WHICH WE WILL BLT UP
MOV #NUM1,D ;POINTER TO THE START OF NUM1
ADD B,NUM1E ;MAKE BOTH THE MAXIMUM
2$: MOV A,C ;COPY POINTER TO THE END
ADD B,C ;THE NUMBER OF BYTES WE ARE MOVING IT UP BY
BLTLOP: MOVB -(A),-(C) ;BLT DOWN THE NUMBER
CMP A,D ;POINTER TO THE START OF THE NUMBER
BNE BLTLOP
CLRLOP: CLRB -(C) ;CLEAR OUT THE REST OF THE AREA
CMP C,D
BNE CLRLOP ;NOW WE HAVE THE NUMBERS THE SAME LENGTH IN NUM1 AND 2
SINCAL: MOV NUM1E,A ;THE NUMBER OF BYTES TO CONVERT
SUB #NUM1,A ;GET THE LENGTH IN A
TST (P)+ ;IS THE SECOND NUMBER NEGATIVE?
BEQ 1$ ;NO
MOV NUM2E,B ;POINTER TO THE NUMBER TO NEGATE
JSR PC,COMPL ;GET 9'S COMPLEMENT
1$: TST (P)+ ;IS THE FIRST NEGATIVE?
BEQ 2$ ;NO ALL DONE
MOV NUM1E,B ;POINTER TO THE NUMBER
JSR PC,COMPL
2$: RTS PC
STNGML: JSR PC,STNG2U ;GET TWO UNSIGNED ARGUMENTS FOR
MOV #NUM3,A ;GET POINTER TO THE RESULT AREA
MOV #NUM3EN-NUM3,B ;CLEAR OUT THE WHOLE AREA
1$: CLRB (A)+
SOB B,1$
MOV #TMPBLK,A ;GET POINTER TO THE DATA AREA
MOV #NUM1,(A)+ ;POINTER TO THE FIRST ARG
MOV NUM1E,(A)
SUB #NUM1,(A)+ ;GET THE LENGTH OF THE FIRST ARG
MOV #NUM2,(A)+ ;POINTER TO THE SECOND ARG
MOV NUM2E,(A)
SUB #NUM2,(A)+ ;GET THE LENGTH OF THE SECOND ARG
CMP TMPBLK+2,TMPBLK+4 ;COMPARE THE LENGTHS
BGE 2$ ;WE WANT THE FIRST ARGUMENT TO BE THE SHORTEST
SPUSH TMPBLK ;EXCH TMPBLK,TMPBLK+4
MOV TMPBLK+4,TMPBLK
SPOP TMPBLK+4
SPUSH TMPBLK+2 ;EXCH TMPBLK+2,TMPBLK+6
MOV TMPBLK+6,TMPBLK+2
SPOP TMPBLK+6
2$: SPUSH #NUM3EN ;POINTER FOR THIS PRODUCT TO BE ADDED IN AT
ADD TMPBLK+6,TMPBLK+4 ;MAKE IT POINT TO THE END OF THE SHORTER NUMBER
;;; HERE TMPBLK LOOKS LIKE THIS
;;; TMPBLK: POINTER TO THE LONGER NUMBER
;;; LENGTH OF THE LONGER NUMBER
;;; POINTER TO THE END OF THE SHORTER NUMBER
;;; LENGTH OF THE SHORTER NUMBER
;;; ON THE STACK IS A POINTER TO THE PLACE TO ADD IN THE CURRENT PARTIAL PRODUCT
NXTBYT: DEC TMPBLK+6 ; COUNT OF BYTES LEFT IN THE SHORTER NUMBER
BLT MULDON ;DONE IF IT COUNTS DOWN
DEC TMPBLK+4 ;MOV -(TMPBLK+4),C
MOVB @TMPBLK+4,C
MOV (P),F ;OUTPUT POINTER
DEC (P) ;FOR NEXT TIME
MOV TMPBLK+2,D ;COUNT OF DIGITS IN LONGER NUMBER
MOV TMPBLK,E ;POINTER TO THE LONGER NUMBER
ADD D,E ;SET UP POINTER TO THE END OF LONGER NUMBER
CLR A ;NO CARRY TO START
;;; HERE WE HAVE THE REGISTERS SET UP AS FOLLOWS:
;;; A: CARRY FROM PREVIOUS MUL
;;; B: SCRATCH
;;; C: MULTIPLIER DIGIT FROM SHORT NUMBER
;;; D: COUNT OF DIGITS IN LONGER NUMBER
;;; E: POINTER TO THE NEXT DIGIT IN LONGER NUMBER
;;; F: OUTPUT POINTER
MULLOP: CMP F,#NUM3 ;OVERFLOWED AREA?
BLOS MULBER ;TOO BIG A NUMBER
MOVB -(E),B ;PICK UP NEXT DIGIT IN LONG NUMBER
MUL C,B ;MULTIPLY AND ADD IN CARRIES
ADD A,B
MOVB -(F),A ;AND ADD IN PREVIOUS CONTENTS
ADD A,B
CLR A ;FOR DIVIDE
DIV #10.,A ;A: THE CARRY, B IS THE DIGIT
MOVB B,(F) ;PUT IT BACK
SOB D,MULLOP ;AND DO REST OF LONG NUMBER
TST A ;ANY CARRY OUT OF HIGH PART OF NUMBER?
BEQ NXTBYT ;NO, GO ON TO THE NEXT DIGIT IN THE SHORT NUMBER
CMP F,#NUM3 ;WILL WE OVERFLOW?
BLOS MULBER ;YES
MOVB A,-(F) ;STORE IT AWAY (MUST BE A 0 BYTE (F) NOW)
BR NXTBYT ;GO DO REST OF SHORT NUMBER
MULDON: TST (P)+ ;POP OFF THE START POINTER
MOV #NUM3EN,B ;POINTER TO THE END OF THE NUMBER
MOV #NUM3,A ;POINTER TO THE START OF THE NUMBER TO RETURN
MOV NUM1S,C ;GET SIGN OF FIRST
MOV NUM2S,D ;AND SIGN OF SECOND
XOR D,C ;GET SIGN OF RESULT
JMP RETSNG ;RETURN IT
MULBER: ERROR+RTB ;RESULT TOO BIG
;LINEARIZE TO NUMBERS INTO NUM1 AND NUM2 PUT THE SIGNS INTO NUM1S AND NUM2S
STNG2U: MOV #NUM1,A ;GET POINTER TO THE FIRST NUMBER
JSR PC,LINEAR
MOV B,NUM1S
MOV A,NUM1E ;GET THE END OF THE FIRST NUMBER
MOV #NUM2,A ;GET POINTER TO THE SECOND NUMBER
JSR PC,LINEAR
MOV B,NUM2S
MOV A,NUM2E
RTS PC
;;; DIVIDE TWO STRING NUMBERS
STNGDV: JSR PC,STNG2U ;GET DIVIDEND IN NUM1 DIVISOR IN NUM2
MOV #NUM1,A ;FIND FIRST NON ZERO DIGIT IN DIVISOR
1$: TSTB (A)+
BNE SDIV1
CMP A,NUM1E ;BE SURE WE DONT RUN OFF THE NUMBER
BLO 1$ ;STILL OKAY
SDIVER: ERROR+RTB ;RESULT TOO BIG
SDIV1: MOV #TMPBLK,B ;GET POINTER TO TEMPORARY AREA
TSTB -(A) ;BACK UP POINTER
MOV A,(B)+ ;POINTER TO DIVISOR
SUB NUM1E,A ;GET LENGTH OF IT
NEG A
MOV A,(B)+ ;AND STORE IT
MOV #NUM2,C ;GET POINTER TO THE DIVIDEND
1$: TSTB (C)+ ;STRIP OFF LEADING ZEROS
BNE 2$ ;FOUND A DIGIT
CMP C,NUM2E ;AT END YET?
BLO 1$ ;NO, TRY AGAIN
2$: TSTB -(C) ;BACK UP POINTER
MOV C,(B)+ ;POINTER TO THE DIVIDEND
ADD C,A ;START WITH THE TRIAL DIVIDEND EQUAL IN LENGTH TO DIVISOR
MOV A,(B)+ ;STORE IT
CLR (B)+ ;CLEAR FLAG SAYING THAT DIVIDEND IS BIGGER THAN DIVISOR
MOV #NUM3+1,NUM3E ;LEAVE A DIGIT ON TOP TO BE ZERO IN CASE NO DIVIDES WORK
MOV NUM3E,(B) ;START PUTTING DIGITS AT THE BOTTOM OF NUM3
;;; HERE TMPBLK IS SET UP AS FOLLOWS:
;;; TMPBLK: POINTER TO THE DIVISOR (NON-ZERO DIGIT)
;;; DIVISOR LENGTH
;;; POINTER TO THE START OF THE DIVIDEND WE ARE TRYING TO GET QUOTIENT FOR
;;; POINTER TO THE END OF THE DIVIDEND WE ARE TRYING TO GET QUOTIENT FOR
;;; FLAG SAYING THAT DIVIDEND LENGTH IS > DIVISOR LENGTH
;;; OUTPUT POINTER
DIVLOP: CMP TMPBLK+6,NUM2E ;DONE WITH THE DIVIDEND YET?
BHI DIVDON ;YES
JSR PC,DIVDGT ;GET A DIGIT OF THE QUOTIENT
MOVB A,@TMPBLK+12 ;AND IN OUTPUT DATA
BEQ 2$ ;IF ZERO, DONT MOVE THE START POINTER
TSTB @TMPBLK+4 ;IS THIS DIGIT 0?
BNE 2$ ;WELL, NO, SO LEAVE IT THERE FOR NEXT TIME
INC TMPBLK+4 ;WE ARE DONE WITH THAT DIGIT FOR SURE
1$: INC TMPBLK+6 ;ADD ANOTHER DIGIT ON THE RIGHT SIDE
INC TMPBLK+12 ;POINT TO NEXT SLOT
BR DIVLOP ;DO IT AGAIN
2$: INC TMPBLK+10 ;SET FLAG SAYING THAT DIVIDEND IS BIGGER
BR 1$ ;AND LOOP BACK
DIVDON: MOV NUM1S,C ;GET THE SIGN OF THE DIVIDEND
MOV NUM2S,D ;AND SIGN OF DIVISOR
XOR D,C ;GET SIGN OF RESULT
MOV TMPBLK+12,B ;GET POINTER TO THE END OF THE NUMBER
MOV #NUM3,A ;AND POINTER TO THE START OF THE NUMBER
JMP RETSNG ;RETURN THE NUMBER
;;; DIVIDE UTILITIES
;;; DIVDGT GETS A QUOTIENT DIGIT
DIVDGT: JSR PC,DIVEST ;ESTIMATE THE DIGIT
SPUSH A ;SAVE THE DIGIT
BEQ 1$ ;IT IS ZERO, SO SKIP THE MUL AND SUBTRACTION
MOV A,C ;COPY IT
JSR PC,DIVMUL ;MAKE DIVIDEND = DIVIDEND - DIVISOR*DIGIT
1$: JSR PC,DIVCMP ;SEE IF ANOTHER DIVISOR FITS IN CURRENT PIECE OF DIVIDEND
BEQ 2$ ;YEP, SUBTRACT IT OFF
TST TMPBLK+10 ;ARE WE CURRENTLY ONE DIGIT LONGER?
BEQ 4$ ;NO, JUST RETURN
MOV TMPBLK+4,C ;GET POINTER TO THE DIVIDEND
TSTB (C)+ ;SKIP IT, SHOULD BE ZERO
TSTB (C) ;IS THE NEXT DIGIT 0?
BNE 4$ ;NO, STILL WILL BE ONE LONGER NEXT TIME
CLR TMPBLK+10 ;OTHERWISE CLEAR FLAG, AND INCREMENT START
INC TMPBLK+4 ;SO THAT WE WIN NEXT LEVEL UP
4$: SPOP A ;GET BACK DIGIT
RTS PC ;AND RETURN
2$: INC (P) ;QUOTIENT DIGIT IS REALLY ONE BIGGER
MOV #1,C ;MULTIPLY BY 1
JSR PC,DIVMUL ;SUBTRACT OFF DIVISOR AGAIN
BR 1$ ;AND TRY AGAIN
;;; DIVEST CONSERVATIVELY ESTIMATES THE QUOTIENT DIGIT
DIVEST: MOV TMPBLK+4,C ;GET POINTER TO THE HIGH ORDER DIGITS OF THE DIVIDEND PIECE
TST TMPBLK+10 ;IS THE DIVIDEND LONGER?
BNE DIVES1 ;YES, SO TAKE THE NEXT TWO DIGITS FROM DIVIDEND
MOVB (C)+,B ;GET THE FIRST DIGIT
;;; HERE THE FIRST DIGIT OR TWO OF DIVIDEND IS IN B, WE DIVIDE BY A ROUNDED UP DIVISOR DIGIT
DIVES2: MOVB @TMPBLK,C ;GET FIRST DIGIT OF DIVISOR
INC C ;ROUND UP
CLR A ;FOR THE DIVIDE
DIV C,A ;GET QUOTIENT IN A FOR TRIAL
RTS PC ;AND RETURN
;;; HERE THE DIVIDEND PIECE IS ONE LONGER THAN THE DIVISOR, SO TAKE THE FIRST TWO DIGITS
DIVES1: MOVB (C)+,B ;GET THE FIRST
MUL #10.,B ;AND ADD IN THE SECOND
MOVB (C)+,A
ADD A,B
BR DIVES2 ;NOW CONTINUE AS NORMAL
;;; DIVCMP SEES IF ANOTHER DIVISOR WILL FIT IN THE DIVIDEND PIECE WE ARE WORKING ON
DIVCMP: MOV TMPBLK+4,A ;GET POINTER TO THE DIVIDEND PIECE
MOV TMPBLK,B ;GET POINTER TO THE DIVISOR
MOV TMPBLK+2,C ;GET COUNT OF THE DIVISOR
TST TMPBLK+10 ;IS THE DIVIDEND PIECE ONE LONGER THAN THE DIVISOR
BNE DVCMP1 ;YES, COMPARE SPECIALLY
DVCMPL: CMPB (A)+,(B)+ ;COMPARE THE DIVIDEND TO THE DIVISOR
BGT DVCMPF ;FAIL IF THE DIVIDEND IS BIGGER
BLT DVCMPS ;SUCCEED IF IT IS SMALLER
SOB C,DVCMPL ;IF EQUAL KEEP TRYING
;;; IF EXACTLY EQUAL, FAIL
DVCMPF: SEZ
DVCMPS: RTS PC
DVCMP1: TSTB (A)+ ;IF THE FIRST DIGIT ISNT ZERO, THEN WE FAIL
BNE DVCMPF
BR DVCMPL ;IF IT IS, COMPARE THE REST OF THE NUMBER
;;; DIVMUL MULTIPLIES THE DIVISOR BY A DIGIT, THEN SUBTRACTS IT FROM A PIECE OF THE
;;; DIVIDEND
DIVMUL: CLR A ;CARRY HERE
MOV TMPBLK+2,D ;LENGTH OF THE DIVISOR
MOV D,E ;COPY IT
ADD TMPBLK,E ;AND GET POINTER TO THE END OF THE DIVISOR
MOV TMPBLK+6,F ;WHERE TO START SUBTRACTING FROM (END OF THE DIVISOR PIECE)
DVMULL: MOVB -(E),B ;MUL -(E),C => B
MUL C,B
SUB B,A ;THIS IS THE CARRY (WILL ALWAYS BE NEGATIVE)
DVMUL1: MOVB -(F),B ;GET THE DIGIT TO SUBTRACT IT FROM
ADD A,B ;WELL A IS NEGATIVE SO THIS IS A SUBTRACT
SXT A ;FOR DIVIDE
DIV #10.,A ;GET THE DIGIT AND THE CARRY
TST B ;IS THE REMAINDER NEGATIVE?
BGE 1$ ;NO, SO IT IS OKAY, THERE CAN'T BE A CARRY
ADD #10.,B ;GET THE DIGIT BY 9'S COMPLEMENT
DEC A ;CARRY IS ONE MORE NEGATIVE
1$: MOVB B,(F) ;STORE BACK THE DIGIT
SOB D,DVMULL ;GO UNTIL WE ARE DONE WITH THE DIVISOR
TST A ;CARRY?
BNE 2$ ;YES, WE WILL HAVE TO CONTINUE
RTS PC
2$: CLR B ;THIS IS THE SUBTRAHEND
INC D ;TO FAKE OUT THE SOB
BR DVMUL1 ;GO BACK AN PROPOGATE CARRY
.GLOBL MXNUML
;LINEARIZE A NUMBER OFF THE S PDL, A POINTS TO AREA, A IS RETURNED POINTING
;PAST THE END OF NUMBER, B IS THE SIGN OF THE NUMBER 0=POS. 1=NEG
LINEAR: CLR (A)+ ;CLEAR THE FIRST TWO DIGITS
CLR -(P) ;THE SIGN FLAG
SPUSH A ;SAVE THE REGS
MOV @S,B ;GET THE ARGUMENT
MOV #LSTR,A ;CONVERT IT TO LSTR
JSR PC,CONVERT ;TRY AND CONVERT
BNE 1$
ERROR+WTAB ;WRONG TYPE OF ARG
1$: SPOP E ;GET BACK POINTER
MOV #MXNUML,F ;COUNTER FOR THE MAXIMUM LENGTH OF NUMBERS
JSR PC,INSTR ;START THE STRING
BEQ LNRDON ;NO STRING WE MUST BE DONE
CLR B ;LEADING ZERO FLAG
CMP D,#'+ ;WAS IT PLUS?
BEQ LNRLOP ;YES, JUST LOOP
CMP D,#'- ;WAS IT MINUS
BNE LNRLP1 ;NO, TREAT IT LIKE A NUMBER
COM 2(P) ;SET SIGN FLAG
LNRLOP: JSR PC,@(SP)+ ;CALL COROUTINE TO GET CHARACTER
BEQ LNRDON ;WE ARE DONE NOW
LNRLP1: SUB #'0,D ;CONVERT IT FROM ASCII
BEQ 3$ ;IT IS ZERO, CHECK LEADING 0 FLAG
BLT 1$ ;ERROR IF NOT A DIGIT
CMP #'9-'0,D ;IS IT TO BIG
BHIS 2$ ;IT IS A DIGIT
1$: ERROR+WTA ;WRONG ARGUMENT
3$: TST B ;IGNORE ZEROS?
BEQ LNRLOP ;YES, IGNORE THE ZEROS
2$: INC B ;WE ARE PLACING A DIGIT, NO LONGER IGNORE ZEROS
MOVB D,(E)+ ;PUT THE BYTE AWAY
SOB F,LNRLOP ;DO FOR ALL THE BYTES
JSR PC,@(SP)+ ;SEE IF THERE IS ANOTHER NUMBER
BEQ LNRDON ;NOPE, WIN
ERROR+RTB ;NUMBER TO BIG
LNRDON: SPOP B ;GET BACK THE SIGN FLAG
ADD #2,S ;POP OFF THE ARGUMENT
MOV E,A ;PUT BACK POINTER INTO A
RTS PC
; GET THE 9'S COMPLEMENT OF A NUMBER WHOSE END IS POINTED TO BY B, LENGTH IN A
COMPL: SPUSH A
MOV #1,C ;ADD THE CARRY IN
COMPLP: MOVB -(B),D ;GET THE NUMBER TO CONVERT
SUB #9.,D ;COMPLEMENT IT
NEG D
ADD C,D ;ADD THE CARRY
CLR C ;CLEAR THE CARRY
CMP D,#10. ;IS IT TOO BIG?
BLT 1$ ;NO, CLEAR TEH CARRY AND GO AWAY
SUB #10.,D ;MAKE IT SMALL AGAIN
INC C
1$: MOVB D,(B) ;PUT BACK COMPLEMENTED BYTE
SOB A,COMPLP ;GO BACK FOR ALL THE BYTES
SPOP A
RTS PC
.ENDC
.SBTTL LIST AND WORD OPERATIONS
SENTEN:
SENT.: CLR C
TST D
SENT.1: BLE SENT.R ;RETURN
MOV @S,B ;ARGUMENT. LEAVE ON S-PDL FOR GARBGE COLLECTOR
MOV B,A
BIC #7777,A ;LEAVE ONLY DATA TYPE
CMP #LIST,A
BEQ SENT.S ;ARG IS LIST
CMP #ATOM,A
BNE SENT.2 ;ARG IS LSTR OR INUM
;ARG IS AN ATOM
SENT.A: JSR PC,.LOAD ;CONVERT ATOM TO LSTR
MOV #LSTR,A
SENT.2: BIS C,A ;C POINTS TO PREVIOUS STUFF OF SENTENCE
JSR PC,GRBAD
SENT.3: MOV C,GCPREV ;POINTER TO PREVIOUS STUFF OF SENTENCE
BIS #LIST,GCPREV ;GARBAGE COLLECTOR NEEDS RIGHT DATA TYPE
SENT.4: JSR PC,SPOPT ;POP S
DEC D ;COUNTER
BR SENT.1
SENT.S: BIT #7777,B ;ARGUMENT IS A LIST
BEQ SENT.4 ;EMPTY
TST C ;0 IF FIRST TIME CALLED
BEQ SENS.1 ;NO NEED TO COPY
;SECOND OR LATER TIME THROUGH
SENS.2: JSR PC,COPYL ;COPY LIST. RETURN POINTER IN B
BIC #170000,GCPREV ;CLEAR DATA TYPE
BIS GCPREV,A ;POINTER TO PREVIOUS STUFF
JSR PC,.STP1 ;C STILL POINTS TO LAST NODE COPIED
SENS.1: BIC #170000,B ;LEAVE POINTER ONLY
MOV B,C
BR SENT.3
;RETURN. POINTER TO SENTENCE IN C
SENT.R: BIS #LIST,C
CLR GCPREV
PUSHS C
CLZ
RTS PC
.GLOBL GCP1,UEL ;025
LIST.P:
SAVE #ORTC
LIST1: CLR C
LIST.1: DEC D ;COUNT
BLT LIST.9 ;DONE
MOV @S,B
MOV B,A
BIC #7777,A ;LEAVE DATA TYPE ONLY
LIST.2: BIS C,A ;POINTER TO REST OF LIST
JSR PC,GRBAD
MOV C,GCPREV ;PROTECT FROM GARBAGE COLLECTOR
BIS #LIST,GCPREV ;GAR. COLL. NEEDS RIGHT DATA TYPE
JSR PC,SPOPT
BR LIST.1 ;GET NEXT ARG
LIST.9: CLR GCPREV
BIS #LIST,C
RTS PC
FPUT:
CLR F
BR LPUT69
LPUT:
MOV #<LPUT1-FPUT1>,F
LPUT69: SAVE #ORTC
DEC D
BGT 1$
ERROR+UEL ;NEED AT LEAST 2 ARGS
1$: JSR PC,GLWARG
BEQ 2$ ;LIST
ERROR+WTA ;FIRST ARG MUST BE LIST
2$: ADD F,PC ;CHOOSE BETWEEN LPUT AND FPUT
FPUT1: MOV B,A ;POINTS TO ARG
BIC #170000,A ;CLEAR DATA TYPE
JSR PC,SPOPT
MOV @S,B ;FIRST ELEMENT TO BE PUT
MOV B,C
BIC #7777,C ;THIS DATA TYPE WILL BE SET INTO A
DEC D
BR LIST.2
LPUT1: JSR PC,COPYL ;COPY LIST. RETURN PTR IN B
MOV B,GCP1
JSR PC,SPOPT ;POP 1ST ARG
JSR PC,LIST1 ;LIST REST OF ARGS
TST F
BEQ LPUT2
BIC #170000,C ;POINTER TO THAT LIST
MOV C,D ;SAVE IT
MOV F,C ;POINTER TO LAST NODE OF COPIED LIST
JSR PC,.LDP1
BIS D,A ;JOIN COPIED LIST TO LIST OF ARGS
JSR PC,.STP1
MOV GCP1,C
LPUT2: CLR GCP1
RTS PC
WORD: CLR GCPREV ;USED AS A FLAG LATER
CLR C
TST D
WORD.1: BLE WORDR
MOV @S,B ;GET ARG, BUT LEAVE ON STACK
.IFZ FPPF
CMP B,#LNUM ;IS ARG NUMBER?
BLO WORD.2
CMP B,#<LNUM+10000>
BLO WORD.N ;NUMBER
.IFF
MOV B,A ;DOES B POINT TO INUM OR FNUM
BIC #170000,A
CMP #INUM,A
BEQ WORD.N
CMP #FNUM,A
BEQ WORD.N
.ENDC
WORD.2: MOV #LSTR,A
JSR PC,CONVERT
BNE 1$
ERROR+WTAB
1$: BIT #7777,B ;IS ARG THE EMPTY WORD
BEQ WORD.4 ;YES
TST GCPREV ;IS 0 FIRST TIME THROUGH
BEQ WORD.3
;SECOND OR LATER ARG
JSR PC,CPYSTR ;COPY STRING
WORD.6: JSR PC,.LDP1 ;LAST NODE OF COPIED STRING
BIC #170000,GCPREV ;CLEAR DATA TYPE
BIS GCPREV,A ;BIS POINTER TO PREVIOUS STUFF
JSR PC,.STP1 ;STORE BACK
WORD.3: BIC #170000,B
BIS #LSTR,B ;GAR. COLL. NEEDS RIGHT DATA TYPE
MOV B,GCPREV ;POINTER TO PREVIOUS STUFF
WORD.4: JSR PC,SPOPT ;POP S
DEC D
BR WORD.1
;ARGUMENT IS NUMBER. CONVERT TO STRING
WORD.N:
.IFZ FPPF
JSR PC,.CINLS
.IFF
.CLNLS: MOV B,A
BIC #170000,A
CMP #INUM,A
BEQ .CLNL1
JMP .CINLS
.CLNL1: JMP .CFNLS
.ENDC
TST GCPREV ;IS 0 FIRST TIME THROUGH
BEQ WORD.3 ;IS FIRST ARG
BR WORD.6 ;SECOND OR LATER, BUT DON'T RECOPY!!
;RETURN
WORDR: MOV GCPREV,C
BIS #LSTR,C
CLR GCPREV
JMP ORTC
MEMBER: JSR PC,GLWARG ;GET A LIST OR WORD ARGUMENT
BNE MEM.WD ;ITS A WORD
MOV B,GCPREV ;PROTECT THIS FROM THE GC
SAVE B ;SAVE POINTER TO NEXT NODE
ADD #2,S ;AND POP IT OFF
JSR PC,GLWARG ;GET A LIST OR WORD ARGUMENT
MOV B,@S ;PROTECT THE ARGUMENT
MEMLP: SPOP A ;GET POINTER TO THE THING WE ARE LOOKING FOR
BIT #7777,A ;IS IT EMPTY
BEQ MEMFLS ;YES, RETURN IT
MOV A,GCPREV ;SAVE IT
JSR PC,.LOADA ;LOAD IT INTO A,,B
SPUSH A ;SAVE POINTER TO BUTFIRST
MOV @S,C ;GET THE OBJECT TO COMPARE AGAINS
JSR PC,EQUAL1 ;ARE THEY EQUAL?
BEQ MEMLP ;NOT EQUAL, TRY THE NEXT ELEMENT
TST (P)+
MOV GCPREV,A ;GET BACK THE LIST TO RETURN
MEMFLS: BIC #170000,A ;CLEAR IT'S TYPE
BIS #LIST,A ;IT'S A LIST
MOV A,@S ;AND RETURN
MEMRT: CLR GCPREV ;NO GC PROTECTION ANY MORE
CLZ ;RETURN A VALUE
RTS PC
MEMWDF: MOV #LSTR,@S ;RETURN EMPTYP WORD
BR MEMRT ;AND RETURN
;HERE FIND THE CHARACTER IN THE WORD THAT IS EQ TO THE FIRST CHAR OF THE SEARCHED
;FOR WORD
MEM.WD: MOV B,GCPREV ;SAVE THE WORD TO SEARCH THROUGH
ADD #2,S ;POP IT OFF
JSR PC,GLWARG ;GET THE OBJECT TO LOOK FOR
BEQ MEMWDF ;ITS A LIST, CANT SEARCH FOR THAT IN A WORD!!
JSR PC,INSTR ;IS THERE A CHARACTER?
BEQ MEMWDF ;NO, JUST RETURN EMPTYP WORD
TST (P)+ ;POP OFF CO-ROUTINE LINKAGE
MOV D,F ;SAVE THE CHARACTER TO LOOK FOR, AND DESTROY CO-ROUTINE
MOV GCPREV,B ;GET BACK POINTER TO THE WROD TO SEARCH FOR
MOV #INSTR,-(P) ;CALL THE SUBROUTINE TRICKILY
MWDLP: JSR PC,@(P)+ ;GET THE NEXT CHARACTER
BEQ MEMWDF ;NO MORE, RETURN EMPTY WORD
CMP D,F ;ARE THEY EQUAL?
BNE MWDLP ;NO, CHECK THE NEXT CHARACTER
TST (P)+ ;POP OFF CO-ROUTINE
MOV A,B ;THE REST OF THIS WORD (INCLUDING THE CHAR IN D)
MOV C,A ;THE POINTER TO THE REST OF THE WORD
JSR PC,GRBAD ;GET A NODE WITH THEM IN IT
BIC #170000,C ;CLEAR THE TYPE
BIS #LSTR,C ;MAKE IT AN LSTR
MOV C,@S ;AND RETURN IT
BR MEMRT
FIRST:
JSR PC,GLWANE
BEQ F.SENT ;ARG IS SENTENCE
;ARG IS WORD
JSR PC,INSTR ;RETURN ONE CHAR IN D
BNE F.WTA9 ;FOUND A CHAR
F.WTA: ERROR+WTA ;NO CHARS IN STRING
F.WTA9: TST (SP)+ ;POP OFF CO-ROUTINE LINK
MOV D,B
F.STOR: CLR F
JSR PC,ACTSTO ;STORE THE CHAR.
POPS C
BIC #170000,C
BIS #LSTR,C ;POINTER TO THE NODE OF THE CHAR
JMP ORTNC
F.SENT: MOV B,C
JSR PC,.LDP2
JMP ORTNA
BUTFIRST:
JSR PC,GLWANE
BEQ BF.SEN
;ARG IS WORD
JSR PC,INSTR ;RETURN ONE CHAR
BEQ F.WTA ;NO CHARS IN STRING
TST (SP)+
;A CONTAINS FIRST 2 CHARS OF THE STRING
;BUT IT MAY ONLY HAVE ONE.
BIT #377,A ;IS TOP CHAR OF A 0?
BEQ BF.W1
BIT #77400,A
BEQ BF.W1 ;YES. ONLY ONE CHAR IN A
CLRB A ;KILL THE FIRST CHAR
MOV A,B
MOV C,A ;POINTER TO REST
JSR PC,GRBAD
BF.W1: BIC #170000,C
BIS #LSTR,C
JMP ORTNC
;ARG IS SENTENCE
BF.SEN: MOV B,C
JSR PC,.LDP1 ;POINTER TO REST OF SENTENCE
BIC #170000,A ;LEAVE ONLY POINTER
BIS #SENT,A
JMP ORTNA
LAST:
JSR PC,GLWANE
BEQ L.SENT ;ARG IS SENTENCE
;ARG IS WORD
MOV B,C
SPUSH #INSTR1 ;ADDRESS OF CO-ROUTINE
CLR D
L.W1: MOV D,B ;SAVE LAST CHAR
JSR PC,@(SP)+ ;RETURNS CHAR IN D
BNE L.W1 ;FOUND ONE
TST B ;STRING DONE
BNE F.STOR ;STORE THE CHAR AND RETURN
ERROR+WTA ;NO CHARS FOUND
L.SEN1: MOV A,B
;ARG IS SENTENCE
L.SENT: JSR PC,.LOAD
BIT #7777,A ;LAST NODE OF SENTENCE YET?
BNE L.SEN1
L.SRET: JMP ORTNB
BUTLAS: JSR PC,GLWANE
BEQ BL.SEN ;ARG IS A SENTENCE
;ARG IS A WORD
JSR PC,CPYSTR ;COPY STRING.
JSR PC,.LDP2 ;LAST NODE OF NEW STRING
SWAB A
BNE 2$ ;THE LAST CHARACTER IS REALLY THERE
CMP B,C ;IS THERE ONLY ONE NODE
BNE 1$ ;MORE TAN ONE NODE
CLR B ;ANSWER IS EMPTY WORD
BR 3$
1$: MOV C,F ;SAVE THIS NODE POINTER
SPUSHS B
MOV B,C ;POINTER TO HEAD OF LIST
4$: JSR PC,.LOADC ;LAOD THE NODE
BIC #170000,A ;FLUSH TYPE
CMP A,F ;DOES IT POINT TO ME?
BEQ 5$
MOV A,C
BR 4$
5$: MOV #SSTR,A
JSR PC,.STORE
SPOPS B
BR 3$
2$: CLRB A ;CLEAR LAST CHAR
JSR PC,.STP2 ;STORE NODE BACK
3$: BIS #LSTR,B ;POINTER TO THE WORD
JMP ORTNB
;ARG IS A SENTENCE
BL.SEN: JSR PC,COPYL ;COPY LIST
MOV E,C ;POINTS TO NEXT TO LAST NODE
BEQ BL.SR ;ANSWER IS EMPTY
JSR PC,.LDP1
BIC #7777,A
JSR PC,.STP1
MOV B,C
BL.SR: BIS #LIST,C
JMP ORTNC
.GLOBL LSTRCV ;031
;INPUT IS NUMBER. OUTPUT IS THE CHARACTER CORRESPONDING TO THAT NUMBER
CHAR: JSR PC,G1IARG ;B,,C _ NUMBER
MOV C,B
BIC #177400,B
MOV #SSTR,A
JSR PC,GRBAD
BIS #LSTR,C
JMP ORTC
;INPUT IS WORD, OUTPUT IS # OF FIRST CHAR
ASCI: JSR PC,LSTRCV ;CONVERT TO LSTR
JSR PC,.LOAD ;GET THE FIRST NODE
BIC #177400,B ;GET A 8 BIT CHARACTER
JMP R1NARG
COUNT:
JSR PC,GLWARG
BEQ CT.SEN
;ARG IS WORD
MOV B,C
CLR B
MOV #INSTR1,-(SP) ;ADDRESS OF A CO-ROUTINE
CT.W1: INC B ;INCREMENT COUNTER
JSR PC,@(SP)+ ;RETURNS CHAR IN B
BNE CT.W1
DEC B ;WHEN RETURNS HERE, NO MORE CHARS
CT.ORT: POPS C
JMP R1NARG ;C IS A THROW-AWAY
;ARG WAS A SENTENCE
CT.SEN: MOV B,C
JSR PC,CLE ;RETURNS NUMBER OF LIST ELEMENTS IN B
BR CT.ORT
;COPY LIST.
; CALL WITH B POINTING TO LIST
; RETURNS B POIOTING TO NEW LIST, C POINTING TO LAST NODE
COPYL: CLR E ;WILL POINT TO 2ND NODE FROM LAST
CLR F
BIT #7777,B
BEQ COPYR1
COPYL1: BIT #7777,B
BEQ COPYLR ;DONE
JSR PC,.LOAD
MOV F,E ;LISTB PLACES LAST NODE PTR INTO F
JSR PC,LISTB
MOV A,B
BR COPYL1
COPYLR: MOV F,C ;LISTB KEEPS PTR TO LAST NODE OF LIST IN F
POPS B ;LISTB KEEPS POINTER TO NEW LIST ON S.
COPYR1: RTS PC
;COPY STRING
;CALL WITH B POINTING TO STRING TO BE COPIED,
;ASSUMES THAT INPUT STRING HAS BEEN GARBAGE COLLECT PROTECTED ALREAEDY
;B POINTS TO FIRST NODE OF NEW STRING, C POINTS TO LAST
CPYSTR: MOV #INSTR,A
MOV D,-(SP)
MOV E,-(SP)
MOV F,-(SP)
MOV A,-(SP) ;ADDRESS OF INPUT STRING ROUTINE
CLR F
OUTSTR: JSR PC,@(SP)+ ;CALL INPUT STRING CO-ROUTINE
BEQ OSTRE1 ;INPUT STRING DONE
OSTR1: MOV D,B ;SAVE CHARACTER
JSR PC,@(SP)+ ;CALL INPUT STRING CO-ROUTINE
BEQ OSTRE2 ;INPUT STRING DONE
OSTR2: SPUSH A ;SAVE REGISTERS USED BY INPUT STRING
SWAB D
BIS D,B ;BIS SECOND CHARACTER
JSR PC,ACTSTO ;ACTUAL STORE
SPOP A
BR OUTSTR
;INPUT STRING HAS ENDED
OSTRE2: JSR PC,ACTSTO ;STORE CHAR IN B
OSTRE1: POPS B ;POINTER TO FIRST NODE OF STRING
MOV F,C ;POINTER TO LAST NODE
BIC #170000,B
BIC #170000,C
.RDEF: CLR GCP1
MOV (SP)+,F
MOV (SP)+,E
MOV (SP)+,D
SEZ
OSTRR: RTS PC
;ACTUALLY STORE OUTPUT NODE
ACTSTO: MOV #SSTR,A
JMP LISTB
;INPUT STRING
;A CO-ROUTINE THAT HANDS BACK A CHARACTER IN BOTTOM BYTE OF D
;DOES RTS PC WHEN INPUT STRING FINISHED
INSTR: MOV B,C
INSTR1: BIT #7777,C
BEQ OSTRR ;RTS PC
JSR PC,.LDP2I
MOVB A,D
BIC #177400,D ;CLEAR TOP BYTE
BEQ INSTR2 ;NULL CHAR
JSR PC,@(SP)+ ;RETURN TO CO-ROUTINE
INSTR2: CLRB A
SWAB A
MOV A,D
BIC #177400,D
BEQ INSTR1 ;NULL CHAR
JSR PC,@(SP)+ ;RETURN TO CO-ROUTINE
BR INSTR1
;LIKE INSTR, EXCEPT GETS CHAR FROM TEXT STRING (NOT NODE SPACE)
;NOTE -- ENTER AT INTXT
INTXT0: JSR PC,@(P)+
INTXT: MOVB (C)+,D
BNE INTXT0 ;BR IF NOT END OF TEXT
RTS PC
.GLOBL HNV,TOPS1 ;034
.GLOBL FLAGS2,NBKTS ;035
MAKE:
MMAKE9: POPS TOPS ;PUT VALUE INTO TOPS
MOV @S,B
MOV B,A
BIC #7777,A
CMP #ATOM,A ;IS TYPE ATOM?
BNE MAKE2
MAKE4: MOV #VBIND,A ;YES< SET VARIABLE BINDING?
JSR PC,.BIND
MAKE1: POPS A
JMP CLRTP1
MAKE2: CMP #LSTR,A
BEQ MAKE3
MAKE5: ERROR+WTAB ;WRONG TYPE OF ARG
MAKE3: BIT #7777,B
BEQ MAKE5
MOV TOPS,@S
MOV B,TOPS ;FOR .INTRN
JSR PC,UINTRN ;.INTRN FOR STRINGS THAT MAY INCLUDE NULL CHARS
MOV @S,TOPS
BIS #ATOM,B
MOV B,TOPS1
BR MAKE4
DOTS: JSR PC,GETVAL ;GET VALUE IF IT HAS ONE
BNE 1$
ERROR+HNV ;HAS NO VALUE
1$: PUSHS B
CLR TOPS
CLZ
RTS PC
THINGP: JSR PC,GETVAL ;DOES IT HAVE A VALUE?
BEQ THNGPF ;NO
JMP RTTRUE
THNGPF: JMP RTFALS
GETVAL: JSR PC,GUOEB ;GET UOE PTR FROM S INTO B
BEQ GETVA1
MOV #VBIND,A
JSR PC,.BINDL
BEQ GETVA1
TST B
GETVA1: RTS PC ;HAS NO VALUE (UNBOUND LOCAL)
GUOEB: POPS B ;GET UOE OR LSTR IN B FROM S
MOV B,A ;SKIP IF UOE
BIT #7777,A ;EMPTY?
BEQ GUOE5
BIC #7777,A
CMP #ATOM,A
BEQ GUOE1
CMP #LSTR,A
BEQ GUOE2
GUOE5: ERROR+WTAB ;.(B). ISWRONG TYPE OF ARG
GUOE2: MOV B,TOPS
JMP UOBSCH ;.OBSCH FOR STRINGS THAT HAVE NULL CHARS
GUOE1: CLZ
RTS PC
;PRINT TOP (C) THINGS ON S
FPRINT: INC NBKTS ;PRINTS OUTER [,]'S
PRINT: SAVE D
JSR PC,REVS ;DOESNT "
POP C
JSR PC,TYPE1
JSR PC,.CRLF
SEZ
RTS PC
TYPE: SAVE D
JSR PC,REVS
POP C
JSR PC,TYPE1 ;PRINT WITHOUT CRLF AT END
SEZ
RTS PC
TYPE1: DEC C
BLT 1$
BIS #DPQF+CPTBF,FLAGS2 ;DONT PRINT QUOTE BEFORE STRINGS
;BUT DO PRINT % AS BLANK
JSR PC,PRS1
POPS A
BR TYPE1
1$: BIC #DPQF+CPTBF,FLAGS2
RTS PC
.IFNZ LSIHAK
LOAD:
.IFZ DMPCAS
MOV #1,D ;TO LOGO. THE SITS RTN WILL THEN INPUT THE CONTENTS
JSR PC,SETTIM
JSR PC,TYO ;OF THE FILE TO LOGO
JSR PC,RESTTY
MOV #1,D ;ONE THING TO PRINT
JSR PC,TYPE1
JSR PC,.CRLF
.IFF
STLANC
ENGINS <PRTXT <START TAPE>>
ENDENG
FRINS <PRTXT <PARTIR LA CASSETTE>>
ENDLAN
.ENDC
JSR PC,LSTIG ;SET TTY INPUT TO IMAGE WITH BIG BUFFER
CLR LSILSC ;CLEAR LOST CAHRS COUNT
MOV PC,REDFLG
SEZ
RTS PC
ENDFIL: JSR PC,LSTRES ;RESTORE REAL BUFFERS
CLR REDFLG
TST LSILSC
BEQ 1$
PRTXT <LOST SOME CHARS!>
CLR LSILSC
1$: SEZ
RTS PC
DUMP:
STLANC
ENGINS <PRTXT <START TAPE RECORDING THEN TYPE SPACE>>
ENDENG
FRINS <PRTXT <COMMENCER L'ENREGISTREMENT ET TAPER UN ESPACE>>
ENDLAN
JSR PC,ONETYI
MOV PC,WRTFLG
JSR PC,SETTIM ;SET TTY TO IMAGE MODE
JSR PC,SHOWAL
STLANC
ENGINS <CPRTXT <!STOP TAPE THEN TYPE SPACE!>>
ENGINS <CPRTXT <ENDFILE>>
ENDENG
FRINS <CPRTXT <!ARRETER L'ENREGISTREMENT ET TAPER UN ESPACE!>>
FRINS <CPRTXT <FINFICHIER>>
ENDLAN
PRCR
JSR PC,ONETYI
JSR PC,RESTTY
CLR WRTFLG
SEZ
RTS PC
.ENDC
.SBTTL PREDICATES, IF, UNTIL AND TEST
EQUAL: MOV S,F
MOV (F)+,B ;ARG1. LEAVE ON STACK FOR GC PROTECTION
MOV (F),C ;ARG2
JSR PC,EQUAL1
BEQ EQ.F ;RETURNS HERE IF FALSE
ADD #4,S
JMP RTTRUE
EQ.F: ADD #4,S
JMP RTFALS
;COMPARE THE DATA ITEM POINTED TO BY B WITH
;THE DATA ITEM POINTED TO BY C.
;SKIP IF THEY ARE EQUAL
EQUAL1: CMP B,C ;ARE THEY EQ?
BEQ EQTRUE ;WONDERFULLY SIMPLE CASE
MOV #7777,E ;AN OFT-USED CONSTANT
MOV B,A
MOV C,D
BIC E,A
BIC E,D
CMP A,D
BNE WEQUAL
CMP #LIST,A
BNE WEQUAL
EQ.LST: BIC #170000,B
BIC #170000,C
CMP B,C
BEQ EQTRUE
TST B
BEQ EQFALS
TST C
BEQ EQFALS
JSR PC,.LOAD
PUSH A
JSR PC,.LDP2I
SPUSH C
MOV A,C
JSR PC,EQUAL1
BEQ EQ.FF
POP B
SPOP C
BR EQ.LST
EQ.FF: CMP (SP)+,(SP)+ ;POP OFF THE POINTERS TO THE BF'S
JSR PC,PPOPT
SEZ
RTS PC
;COMPARE TWO WORDS
.GLOBL EXCH1,GCP2 ;039
.GLOBL FALSE,TRUE ;040
.IFZ FPPF
WEQUAL: MOV #INUM,A
JSR PC,CONVERT ;TRY CONVERTING ARG TO INUM
BEQ EQ.STR ;NOT NUMERIC
EXCH B,C
JSR PC,CONVERT ;TRY CONVERTING 2ND ARG
BEQ EQFALS ;NOT NUMERIC
JSR PC,.LOAD ;A,,B HAVE NUMBER
MOV A,D
MOV B,F
JSR PC,.LOADC
CMP A,D ;COMPARE 2 INTEGERS
BNE EQFALS
CMP B,F
BNE EQFALS
BR EQTRUE
.IFF
WEQUAL: JSR PC,G1NUMS ;IS IT A NUMBER?
BEQ EQ.STR
LDD FA,FB ;IT WAS SO SAVE IT
MOV C,B ;IS THE SECOND A NUM?
JSR PC,G1NUMS
BEQ EQFALS
CMPF FA,FB ;COMPARE THEM
CFCC
BNE EQFALS
BR EQTRUE
.ENDC
;ARG NOT NUMERIC. TRY STRING COMPARE
EQ.STR: MOV #LSTR,A
JSR PC,CONVERT
BEQ EQFALS ;EQUAL NOT DEFINED FOR SNAPS, ETC
EXCH B,C
JSR PC,CONVERT ;TRY CONVERTING 2ND ARG, TOO
BEQ EQFALS ;NOT SAME TYPE AS FIRST ARG
CMP B,C
BEQ EQTRUE
;COMPARE TWO STRINGS. POINTERS IN B AND C.
SPUSH #INSTR1
MOV C,GCP2
CMPSTR: MOV B,GCP1
MOV B,F
CMPST1: BIT E,F ;IS ARG 1 ENDED
BEQ CMPSTE ;YES
SPUSH A ;SAVE A
MOV F,B ;POINTER TO REST OF ARG1
JSR PC,.LOAD
MOV A,F ;POINTER TO REST OF ARG1
SPOP A ;RESTORE A
TSTB B ;IS CHAR REAL OR NULL?
BEQ CMPST2 ;NULL
JSR PC,@(SP)+ ;PUTS 1 CHAR OF ARG 2 INTO B
BEQ CSFAL1 ;ARG 2 ENDED
CMPB D,B ;COMPARE CHARS!!
BNE CSFALS
CMPST2: SWAB B
BIC #177400,B
BEQ CMPST1 ;NULL CHAR
JSR PC,@(SP)+ ;1 CHAR OF ARG 2 IN B
BEQ CSFAL1
CMPB D,B ;COMPARE CHARS!!
BEQ CMPST1
CSFALS: TST (SP)+ ;POP CO-ROUTINE LINKAGE
CSFAL1: CLR GCP1
CLR GCP2
EQFALS: SEZ
RTS PC
;ARG 1 HAS ENDED
CMPSTE: JSR PC,@(SP)+
BNE CSFALS ;BUT ARG 2 HASN'T ENDED
CLR GCP1
CLR GCP2
EQTRUE: CLZ
RTS PC ;BOTH ENDED AT THE SAME TIME!!!!
;CALL WITH B = POINTER TO STRING IN NODE SPACE
; C = POINTER TO STRING IN DATA SPACE
EQ.TXT: SPUSH #INTXT ;ADDRESS OF CO-ROUTINE
MOV #7777,E ;AN OFT USED CONSTANT
BR CMPSTR
;MORE PREDICATES
GREATR: JSR PC,CMP2IA
BGT RTTRUE
RTFALS:
STLANC
ENGINS <PUSHS #FALSE>
ENDENG
FRINS <PUSHS #FAUX>
ENDLAN
RTNCMP: CLZ
RTS PC
LESSP:
LESS: JSR PC,CMP2IA
BGE RTFALS
RTTRUE:
STLANC
ENGINS <PUSHS #TRUE>
ENDENG
FRINS <PUSHS #VRAI>
ENDLAN
BR RTNCMP
GREQ: JSR PC,CMP2IA
BGE RTTRUE
BR RTFALS
LSEQ: JSR PC,CMP2IA
BLE RTTRUE
BR RTFALS
NUMBP: POPS B
MOV #INUM,A
JSR PC,CONVERT
.IFZ FPPF
BEQ RTFALS ;COULDN'T CONVERT IT
BR RTTRUE
.IFF
BNE RTTRUE
MOV #FNUM,A
JSR PC,CONVERT
BEQ RTFALS
BR RTTRUE
.ENDC
EMPTYP: POPS B
BIT #7777,B
BEQ RTTRUE
BR RTFALS
LISTP: POPS B
BIC #7777,B
CMP #SENT,B
BEQ RTTRUE
BR RTFALS
WORDP: POPS B
BIC #7777,B
CMP #SENT,B
BEQ RTFALS
BR RTTRUE
.IFZ FPPF
;COMPARE TWO INTEGER ARGUMENTS
CMP2IA: JSR PC,G2IARG
;COMPARE 2 INTEGERS IN B,,C & E,,F
.ENDC
CMP2I: CMP E,B
BNE CMP2IR ;CONDITION CODES SET CORRECTLY
CMP F,C
BEQ CMP2IR
BHI CMP2IH
;E,,F < B,,C
CMP #0,(PC)
RTS PC
CMP2IH: TST (PC)
CMP2IR: RTS PC
.IFNZ FPPF
;GET AND COMPARE TWO (FNUM OR INUM) ARGS
CMP2IA: SPUSH A
JSR PC,G2ARG
SPOP A
CMPF FB,FA
CFCC
RTS PC
INTEGE: JSR PC,G1ARG ;GET A FNUM ARG
LDD FA,FB
MOV #INUM,F
JMP .FSTOR
.ENDC
NOT: JSR PC,TSTST ;TEST S SKIP IF TRUE
BEQ RTTRUE
BR RTFALS
BOTH: JSR PC,TSTST
BNE EITH1
JSR PC,SPOPT
BOTH1: BR RTFALS
EITH1: JSR PC,TSTST
BEQ BOTH1
BR RTTRUE ;BOTH ARE "TRUE !!
EITHER: JSR PC,TSTST
BEQ EITH1 ;IS 2ND ONE "TRUE?
JSR PC,SPOPT ;POP 2ND ARG
BR RTTRUE
.GLOBL BRAKE,BRK,CPLN,CTP,FLAGS,FUNLEV,IFLEV,NOPAR,OOP ;042
.GLOBL $ELSE,$IF,$LPAR,$RPAR,CT ;043
.GLOBL .BUG.,IS,NTF ;044
TEST: JSR PC,TSTST ;IS TOP OF S "TRUE"?
BEQ TES1 ;NO, CLEAR FLAG
BIS #TSTFLG,FLAGS ;YES, SET FLAG
BR IFR
TES1: BIC #TSTFLG,FLAGS
BR IFR
IFTRUE: JSR PC,IFTFST ;FLAG SET?
BNE IFR ;YES, CONTINUE
BR IFT1 ;GO ACT LIKE A FAILED IF
IFFALS: JSR PC,IFTFST
BEQ IFR ;YES, CONTINUE
BR IFT1 ;NO STOP
IFTFST: INC IFLEV
BIT #TSTFLG,FLAGS
RTS PC
UNTIL: JSR PC,TSTST
BNE IFR
MOV CPLN,TMPBLK ;STORE THE CURRENT LINE NUMBER
BIT #DORF,FLAGS ;IN A DO OR RUN FRAME?
BNE UNTIL1 ;YES, DO THE UNTIL IN THIS FRAME
TST FUNLEV ;AT TOP LEVEL?
BEQ UNTIL1 ;YES, DO IT IN THIS FRAME
JMP GOUNTL
UNTIL1: BRAKET ;CHECK FOR INFINITE LOOP IN EVLINE
MOV #HEADER,CTP ;POINT AT LINE IN CURLIN
JSR PC,IGNT ;RESET POINTERS TO THE START OF THE LINE
SEZ ;NO OUTPUT
RTS PC
IF: INC IFLEV
JSR PC,TSTST ;TEST S, SKIP IF "TRUE"
BNE IFR
IFT1: CLR NOPAR
JSR PC,STNE
BEQ IFR
BIC #RTF,FLAGS
DEC IFLEV
IFR: SEZ
RTS PC
THEN: TST IFLEV
BGT IFR
ERROR+OOP ;THEN OUT OF PLACE
ELSE: DEC IFLEV
BGE ELSE9
ELSE1: ERROR+OOP ;ELSE OUT OF PLACE
ELSE9: CLR NOPAR
JSR PC,STNE
BEQ IFR
TST IFLEV
BLE ELSE1
BR IFR
STNE: ;SCAN TOO NEXT ELSE, CR OR UNMATCHED );
; SET RTF. SKIP IIF "ELSE"
JSR PC,GNT
CMP #$RPAR,B
BNE STNE4
DEC NOPAR
BGE STNE
BIS #RTF,FLAGS
SEZ
RTS PC
STNE4: CMP #$LPAR,B
BNE STNE5
INC NOPAR
BR STNE
STNE5: TST NOPAR
BGT STNE
.IFNZ ENG
CMP #$ELSE,B
BEQ STNE6
.ENDC
.IFNZ FR
CMP #$SINON,B
BEQ STNE6
.ENDC
STNE1: BIT #CRF,FLAGS
BEQ STNE2
STNE3: BIS #RTF,FLAGS ;IF "CR" SET RTF AND RETURN
BIC #CRF,FLAGS
SEZ
RTS PC
STNE6: BIS #RTF,FLAGS ;IF "ELSE", SET RTF AND SKIP RETURN
RTS PC
STNE2:
.IFNZ ENG
CMP #$IF,CT ;IS "IF", LOOK FOR THE NEXT ELSE!
BEQ STNE7
.ENDC
.IFNZ FR
CMP #$SI,CT
BEQ STNE7
.ENDC
BR STNE
STNE7: JSR PC,STNE
BEQ STNE3
BIC #RTF,FLAGS
BR STNE
.GLOBL SPSWPI
TSTST:
MOV @S,B ;TEST S, SKIP IF TRUE
.IFNZ ENG
CMP B,#FALSE
BEQ TSTF9 ;IT'S "FALSE
.ENDC
.IFNZ FR
CMP B,#FAUX
BEQ TSTF9
.ENDC
.IFNZ ENG
MOV #TRUE,C ;ERROR IF NEITHER "TRUE" OR "FALSE"
JSR PC,EQUAL1
BNE TESTIT
.ENDC
.IFNZ FR
MOV @S,B
MOV #VRAI,C
JSR PC,EQUAL1
BNE TESTIT
.ENDC
.IFNZ ENG
MOV @S,B
MOV #FALSE,C
JSR PC,EQUAL1
BNE TSTF9
.ENDC
.IFNZ FR
MOV @S,B
MOV #FAUX,C
JSR PC,EQUAL1
BNE TSTF9
.ENDC
ERROR+NTF ;NOT "FALSE, EITHER
TSTF9: JSR PC,SPOPT
SEZ
RTS PC ;"FALSE!!
TESTIT: JSR PC,SPOPT
CLZ
RTS PC ;"TRUE!!
REVS: CMP #1,2(P) ;REVERSES THE TOP ((P)+2) THINGS ON S
BLT 1$ ;IF <2 QUIT
RTS PC
1$: CMP #MAXARG,2(P)
BGE 2$
.BUG. ;BARF, WHO ASKED REVS TO SWITCH > 32 THINGS?
2$: PUSH A
SPUSH B
SPUSH C
SPUSH D
MOV 10.(P),C ;GET # TO BE SWITCHED
5$: MOV S,A ;COMPUTE ADDR OF WORD JUST BEYOND BLOCK
MOV C,B
ASL B
ADD A,B
CMP IS,B ;SHOULD WE FORCE A SWAPIN?
BLO 4$ ;YES
ASR C
BEQ 9$
8$: MOV (A),D
MOV -(B),(A)+
MOV D,(B)
DEC C
BGT 8$
9$: JMP RETD
4$: JSR PC,SPSWPI ;SWAP S PDL BACK IN
BR 5$
.SBTTL DOUBLE PRECISION INTEGER ARITHMETIC
.IFZ FPPF
;INTEGER MULTIPLICATION
;CALL WITH ONE DOUBLE PRECISION ARGUMENT IN B,,C
;AND THE OTHER IN E,,F
;RETURNS PRODUCT IN E,,F.
;ALL OTHER ACCUMULATORS (INCLUDING B,C ARE UNCHANGED)
.DPMUL: SPUSH A ;SAVE A
CLR A
DVML: PUSH B
SPUSH C
SPUSH D
SPUSH E
SPUSH F
PUSH B ;STUFF ABS(B,,C)
SPUSH C
SPUSH E ;AND ABS(E,,F)
SPUSH F
CLR -(SP) ;A FLAG FOR NEG. ARGS
TST B ;MAKE SURE ARGS ARE POSITIVE
BGE DVML1
DPNEG B,C
DPNEG 10(P),6(P) ;ALSO ON STACK (FOR DIV)
COM (SP)
DVML1: TST E
BGE DVML2
DPNEG E,F
DPNEG 4(P),2(P)
COM (SP)
DVML2: ADD A,PC ;CHOOSE BETWEEN MUL AND DIV
;DOUBLE PRECISION MULTIPLY (CONT.)
MUL1: TST B ;OVERFLOW UNLESS A1*A2=0
BEQ MUL2
TST E
BNE MDV2 ;OVERFLOW!
EXCH B,E ;WANT ARG1 TO HAVE ZERO HIGH ORDER PART
EXCH C,F
MUL2: CLR -(SP) ;SET B1 AND B2
ASL C
BCC 1$
MOV #100000,(SP) ;B2
1$: ASL F
BCC 2$
ADD #200,(SP) ;B1 (ALSO CLEARS CARRY)
2$: ROR C ;C2
ROR F ;C1
;IF B2*A1>0, THEN OVERFLOW
TST (SP)
BGE MUL3 ;B2=0
TST E ;A1
BNE MDV1 ;OVERFLOW
;DOUBLE PRECISION MULTIPLY (CONT.)
;GET A1*C2*(2**16.)
MUL3:
MOV C,A ;C2*A1
MUL E,A
BCS MDV1 ;CARRY INTO A IS OVERFLOW
MOV B,ANSWER+2 ;SINCE A1*C2 IS HIGH ORDER OF ANSWER
;GET C1*C2 AND ADD INTO ANSWER
MOV C,A ;C1*C2
MUL F,A
MOV B,ANSWER ;LOW ORDER PARTIAL PRODUCT
ADD A,ANSWER+2 ;ADDED TO A1*C2
BVS MDV1 ;OVERFLOW
;GET C2*B1*(2**15.) AND ADD INTO ANSWER
TSTB (SP)
BEQ MUL35 ;B1=0
CLR A
MOV C,B ;GET C2
ASHC #15.,A ;SHIFT C2 LEFT 15 PLACES
ADD B,ANSWER ;DOUBLE PRECISION ADD
ADC ANSWER+2
BVS MDV1
ADD A,ANSWER+2
BVS MDV1
;NOW GET B2*C1*(2**15.) AND ADD INTO ANSWER
MUL35: TST (SP)
BGE MUL4
CLR A
MOV F,B ;GET C1
ASHC #15.,A ;SHIFT C1 LEFT 15 PLACES
ADD B,ANSWER ;DOUBLE PRECISION ADD
ADC ANSWER+2
BVS MDV1
ADD A,ANSWER+2
BVS MDV1
;NOW GET B1*B2*(2**30.)
MUL4: CMP (SP)+,#100200 ;ARE BOTH B1 AND B2 SET
BNE MUL5 ;NO (PRODUCT IS ZERO, OBVIOUSLY)
ADD #40000,ANSWER+2 ;1*2**30. + ANSWER
BVS MDV2 ;OVERFLOW
;PUT ANSWER IN THE RIGHT PLACE
MUL5: MOV ANSWER+2,E ;HIGH ORDER PARTS
MOV ANSWER,F ;LOW ORDER PARTS
TST (SP)+ ;NEGATIVE?
BEQ MUL6
DPNEG E,F
MUL6: ADD #14,SP ;THROW AWAY E,,F, ABS(B,,C) AND ABS(E,,F)
JMP SRETD ;BUT RESTORE THE REST
;OVERFLOW EXITS
MDV1: TST (SP)+ ;POP 2 WORDS + ABS'S
MDV2: ADD #12,SP ;POP 1 WORD + ABS'S
JMP RETF ;RESTORE ALL AC'S AND RTS
;DOUBLE PRECISION DIVIDE
; DIVIDE E,F BY B,C
;RETURN QUOTIENT IN E,F AND REMAINDER IN B,C
.DPDIV: SPUSH A
MOV #<DIV1-MUL1>,A ;ADD TO THE PC IN A WHILE
JMP DVML ;INITIALIZATION.
DIV1: TST B ;IS DEN = 0, 1, OR DOUBLE PRECISION ?
BNE DIV2 ;DOUBLE PRECISION
TST C
BLT DIV2 ;DOUBLE PRECISION (SINCE TOP BIT WAS SET)
;DEN IS SINGLE PRECISION
BEQ MDV2 ;DEN=0. OVERFLOW!
CMP C,#1 ;IS IT 1?
BNE SPDEN1 ;NO
CLR B
CLR C
BR DIV10
SPDEN1: JSR PC,.SPDEN ;DO THE DIVISION
BR DIV10
;DEN IS DOUBLE PRECISION
DIV2: JSR PC,CMP2I ;IS NUM < DEN
BGE DIV5 ;NO
;NUM<DEN. QUOTIENT=0. REM=NUM
DIV4: MOV E,B
MOV F,C
CLR E
CLR F
BR DIV10
;NUM>=DEN.
DIV5: PUSH B ;SAVE DENOMINATOR
SPUSH C
MOV B,A ;MOVE B,,C TO A,,B AND NORMALIZE
MOV C,B
CLR SHFCNT
DIV5A: INC SHFCNT ;COUNT A LEFT SHIFT
ASHC #1,A
BVC DIV5A ;UNTIL SIGN BIT CHANGES (OVERFLOW)
ASHC #-1,A ;UNDO LAST SHIFT
BIC #100000,A ;AND CLEAR SIGN BIT WHICH WAS SET
DEC SHFCNT ;UNCOUNT THE LAST SHIFT
MOV A,C ;DIVIDE BY HIGH-ORDER OF NORMED DIVISOR
JSR PC,.SPDEN ;E,,F _ (E,,F)/(DIVISOR*2^[N-16.])
MOV E,A ;MOV (QUOTIENT*2^[16.-N]) TO A,,B
MOV F,B
ADD #-16.,SHFCNT ;TIMES 2^[N-16.] IS TRIAL QUOTIENT
ASHC SHFCNT,A
;GET TRIAL NUM_(TRIAL QUOTIENT-1)*DEN. COMPARE WITH TRUE NUM
POP F ;E,,F _ SAVED DENOMINATOR
SPOP E
MOV B,C ;B,,C _ A,,B (TRIAL QUOTIENT)
MOV A,B
SUB #1,C ;TRY FIRST WITH Q_Q-1
SBC B
BVS MDV2 ;OVERFLOW
JSR PC,.DPMUL
BEQ MDV2 ;MULTIPLY GOT AN ERROR (HMM!)
;COMPARE NUM TO TEM
MOV B,ANSWER+2 ;SAVE TRIAL QUO
MOV C,ANSWER
;FALLS THROUGH
;FALLS IN
;GET TEM-NUM
MOV SP,D
TST (D)+
SUB (D)+,F
SBC E
BVS MDV2
SUB (D)+,E
BVS MDV2
;TURN INTO NUM-TEM
DPNEG E,F
MOV E,B
MOV F,C
MOV (D)+,F ;E,,F_DEN
MOV (D)+,E
DIV6: TST B ;NUM-TEM
BEQ DIV7
BGT DIV75
;ANSWER TOO BIG. TRY ANSWER _ ANSWER - 2
SUB #2,ANSWER
SBC ANSWER+2
BVS MDV2
;THIS MAKE TEM _ TEM + 2*DEN
ADD F,C
ADC B
BVS MDV2
ADD E,B
BVS MDV2
ADD F,C
ADC B
BVS MDV2
ADD E,B
BVS MDV2
BR DIV6
DIV7: TST C
BEQ DIV9 ;TRIAL QUOTIENT = QUOTIENT !!
;TEM < NUM. EITHER QUOT=QUOT OR QUOT+1
DIV75: JSR PC,CMP2I ;IS REM < DEN
BGT DIV9 ;YES
DIV8: ADD #1,ANSWER ;QUOT _ QUOT + 1
ADC ANSWER+2
BVS MDV2
SUB F,C ;REM _ REM - DEN
SBC B
BVS MDV2
SUB E,B
BVS MDV2
DIV9: MOV ANSWER+2,E
MOV ANSWER,F
DIV10: TST (SP)+ ;NEG. IF ANSWER SHOULD BE NEG.
BGE DIV11
DPNEG B,C
DPNEG E,F
DIV11: ADD #14,SP ;POP ABS(E,,F), ABS(B,,C) AND E,,F
POP D ;RESTORE D
CMP (SP)+,(SP)+ ;THROW AWAY B & C
SPOP A ;RESTORE A
CLZ
RTS PC
;SINGLE PRECISION DENOMINATOR. DOUBLE PRECISION NUMERATOR.
;C=DEN. E,F=NUM. RETURNS C_REM, E,F_QUOTIENT
.SPDEN: SPUSH A
SPUSH B
ASL E ;DOUBLE E,,F
ASL F
ADC E
MOV E,B ;2E/C
CLR A
DIV C,A
MOV A,E ;2*HIGH-QUOTIENT -> E
MOV B,A ;(2REM + 2F)/2 /C
MOV F,B
ASHC #-1,A
DIV C,A
MOV A,F ;LOW-QUOTIENT -> F
MOV B,C ; REMAINDER -> C
ASR E ;HALVE E TO GET PROPER HIGH-QUOTIENT
BCC 1$
BIS #100000,F ;& LOW BIT FROM DOUBLE-E CLOBBERS F'S SIGN BIT
1$: SPOP B
SPOP A
RTS PC
.ENDC
.IFNZ FPPF
;FLOATING DIVIDE AND MULTIPLY FROM REGS B,,C AND E,,F
.DPMUL: PUSH A
CLR A ;SET SWITCH
.DPMU1: FPUSH FA
FPUSH FB
SPUSH C
SPUSH B
LDCIF (P)+,FA
SPUSH F
SPUSH E
LDCIF (P)+,FB ;LOAD FLOATING REGS
ADD A,PC ;WHICH ENTRY?
.DPMU5: MULF FA,FB
BR .DPMU2
.DPMU6: LDD FB,FC ;SAVE FB
DIVF FA,FB
.DPMU2: STCFI FB,-(P) ;STACK QUOTIENT OR PRODUCT
BCS .DPERR ;TOO BIG!?
SPOP E
SPOP F ;LOAD E,,F
TST A
BNE .DPMU4 ;BRANCH ON DIVIDE
.DPMU3: FPOP FB
FPOP FA
SPOP A
CLZ
RTS PC
.DPMU4: STCFI FB,-(P)
LDCIF (P)+,FB ;TRUNCATE QUOTIENT
MULF FA,FB
SUBF FB,FC ;GET REMAINDER
STCFI FC,-(P)
SPOP B
SPOP C ;LOAD B,,C WITH REMAINDER
BR .DPMU3
.DPDIV: TST C ;DIVIDE ENTRY
BNE .DPDI1
TST B ;DON'T DIVIDE BY ZERO
BEQ .DPERQ
.DPDI1: PUSH A
MOV #<.DPMU6-.DPMU5>,A ;SET DIVIDE SWITCH
BR .DPMU1 ;GO DO IT
.DPERR: CMP (P)+,(P)+ ;CLEAR STACK
FPOP FB
FPOP FA
SPOP A
SEZ
.DPERQ: RTS PC
.ENDC
.GLOBL CNVTBL ;051
.SBTTL CONVERSION ROUTINES
;CONVERT
;CALL WITH DESIRED DATA TYPE IN A
;CALL WITH POINTER TO DATA IN B
;IF CONVERSION SUCCEEDS, RETURN POINTER TO CONVERTED DATA IN B AND
;LEAVE A UNCHANGED.
;
;IF CONVERSION FAILS, LEAVE B UNCHANGED,BUT RETURN ITS DATA TYPE IN A
CONVERT:
MOV A,-(SP) ;SAVE A,B,C HERE
MOV B,-(SP)
MOV C,-(SP)
BIC #107777,A ;LEAVE DATA TYPE ONLY
MOV B,C
BIC #107777,C
ASR A ;SHIFT DESTINATION DATA TYPE 3 PLACES
ASR A
ASR A
BIS C,A ;SET SOURCE DATA TYPE IN THE 3 VACATED BITS
ASR A ;AND PLACE THE ENTIRE MESS IN BOTTOM 6 BITS
SWAB A
;(A IS NOW A 6 BIT DISPATCH ADDRESS)
MOVB CNVTBL(A),A ;PICK UP ENTRY FROM TABLE
BIC #177400,A ;CLEAR TOP BYTE
ASL A ;IT IS A BYTE ADDRESS
JSR PC,CNVTOP(A) ;RELATIVE TO CONVERT TOP
BEQ CONV.F ;THE CONVERSION FAILED
MOV (SP)+,C
TST (SP)+ ;DON'T RESTORE B
MOV (SP)+,A
RTS PC
CONV.F: MOV (SP)+,C
MOV (SP)+,B
MOV B,A
BIC #7777,A ;DATA TYPE OF ARG LEFT IN A
TST (SP)+ ;DON'T RESTORE A
;FALLS THROUGH
;CONVERT ROUTINE JUMPS TO THE PROGRAMS HERE
DC CNVTOP,. ;TOP OF CONVERT ROUTINES
;THE ARGUMENT CAN'T BE CONVERTED TO DESIRED DATA TYPE
.CERR: SEZ
RTS PC
DC CA2LS,<<.-CNVTOP>/2>
;CONVERT ATOM TO LSTR
.CATLS: JSR PC,.LOAD
DC CNVNOP,<<.-CNVTOP>/2>
;THE ARGUMENT ALREADY HAS THE DESIRED TYPE
.CNOP: CLZ
RTS PC
DC CSN2IN,<<.-CNVTOP>/2>
;CONVERT SNUM TO INUM. ASSUME NUMBER IN B, RATHER THAN POINTER
.CSNIN: CLR A
TST B ;IS NUM NEGATIVE?
BGE 1$
COM A ;SET TOP PART TO ALL 1'S
1$: JSR PC,GRBAD
BIS #INUM,C ;C POINTS TO NEW NODE
MOV C,B
RTS PC
.GLOBL ABASE ;053
;MORE CONVERSION ROUTINES
DC CIN2SN,<<.-CNVTOP>/2>
;CONVERT INUM TO SNUM. RETURN NUMBER IN B
.CINSN: JSR PC,.LOAD
TST B
SXT C ;SEE IF B'S SIGN EXTENDED FILLS A.
CMP A,C
BNE .CERR
CLZ
RTS PC
DC CSN2LS,<<.-CNVTOP>/2>
;CONVERT SNUM TO LSTR
.CSNLS: JSR PC,.CSNIN ;CONVERT TO INUM FIRST
DC CIN2LS,<<.-CNVTOP>/2>
;CONVERT INUM TO LSTR
.CINLS: SPUSH D
SPUSH E
SPUSH F
JSR PC,.LOAD ;A,B HAS NUMBER
JSR PC,.CINST ;CONVERT TO STRING ON P-PDL
.CINL0: CLR F
MOV #SSTR,A
.CINL1: SPOP B
BEQ .CINL2 ;0 MARKS END OF DIGITS
JSR PC,LISTB ;PUT NEXT 2 CHARS ONTO LIST
BR .CINL1
.CINL2: POPS B ;POINTER TO FIRST NODE OF ANSWER
BIC #170000,B ;CLEAR DATA TYPE
BIS #LSTR,B ;REPLACE BY LSTR
MOV F,C ;GET PTR TO LAST NODE IN STRING
.SRDEF: CLR GCP1
MOV (SP)+,F
MOV (SP)+,E
MOV (SP)+,D
CLZ
RTS PC
;GET NEXT CHARACTER IN B
;SKIP UNLESS NO MORE CHARS
.CNXTD: TST E ;IS THERE MORE NUMBER LEFT
BNE .CNXD1 ;YES
TST F
BEQ .CNXD2
.CNXD1: MOV #10.,C
ADD ABASE,C ;ADD DELTA ARITHMETIC BASE TO C
CLR B
JSR PC,.DPDIV ;C_REM, E,,F_QUO
BEQ .CNXD2
ADD #60,C ;TURN TO ASCII
.CNXD2: RTS PC
.GLOBL TEM1 ;054
;CONVERT INUM TO STRING ON P-PDL
.CINST: MOV (SP),TEM1 ;RETURN ADDRESS
CLR (SP)
MOV #10,D
MOV A,E
BGE .CINI1 ;NUMBER IS POSITIVE
DPNEG E,B ;NUMBER IS NEG
CLR D ;FLAG
.CINI1: MOV B,F
.CINI2: JSR PC,.CNXTD ;GET NEXT DIGIT IN C
BEQ .CINI5 ;NO MORE CHARS
SWAB C
PUSH C
JSR PC,.CNXTD
BEQ .CINI6
BISB C,(SP) ;SET NEW CHAR INTO PREVIOUS ONE
BR .CINI2
.CINI5: ADD D,PC ;NEGATIVE?
SPUSH #<55*256.> ;PUSH A MINUS SIGN IN HIGH BYTE
.CINIR: JMP @TEM1 ;RETURN
BR .CINI7
.CINI6: ADD D,PC ;NEGATIVE?
BIS #55,(SP) ;PUT A MINUS SIGN IN LOW BYTE
JMP @TEM1
.CINI7: TST (SP) ;WERE ANY CHARACTERS GENERATED?
BNE .CINIR ;YES, SO RETURN
SPUSH #<60*256.> ;NO, SO PUSH A "0 IN HIGH BYTE
BR .CINIR
;MORE CONVERSION ROUTINES
DC CLS2SN,<<.-CNVTOP>/2>
;CONVERT LSTR TO SNUM
.CLSSN: JSR PC,.CLSIN ;CONVERT TO INUM FIRST
BEQ .CLNR
JSR PC,.CINSN ;THEN CONVERT TO SNUM
.CLNR: RTS PC ;FAILED
DC CLS2IN,<<.-CNVTOP>/2>
;CONVERT LSTR TO INUM
.CLSIN: BIT #7777,B ;IS B EMPTY
BEQ .CLNR ;CAN'T CONVERT EMPTY
PUSH D
SPUSH E
SPUSH F
MOV B,GCP1 ;POINT TO INPUT. (GETS CLEARED AT .RDEF & .SRDEF)
MOV B,C
CLR E
CLR F
.CLSS0: CLR -(SP) ;A FLAG
JSR PC,INSTR1 ;GET FIRST CHAR IN D
BEQ .CLSS8 ;NO CHARS (HMM)
CMPB D,#53 ;PLUS
BEQ .CLSSA
CMPB D,#55 ;MINUS
BNE .CLSS3 ;NOT + OR -
COM 2(SP) ;-1
.CLSSA: JSR PC,@(SP)+
BEQ .CLSS8
BR .CLSS4
.CLSS1: JSR PC,@(SP)+ ;GET NEXT CHAR INTO D
.CLSS4: BEQ .CLSS9 ;ALL CHARS GOTTEN
.CLSS3: SPUSH C ;SAVE C
SUB #60,D ;CONVERT FROM ASCII
BLT .CLSS7 ;NOT DIGIT
CMPB D,#10.
BGE .CLSS7 ;NOT DIGIT
MOV #10.,C
ADD ABASE,C ;ADD DELTA ARITHMETIC BASE TO C
CLR B
JSR PC,.DPMUL
BEQ .CLSS7 ;TOO BIG
ADD D,F ;ADD NEXT DIGIT IN
ADC E
BVS .CLSS7 ;OVERFLOW
SPOP C
BR .CLSS1
;EITHER A NON-DIGIT CHARACTER WAS FOUND, OR ELSE
;THERE WAS OVERFLOW
.CLSS7: CMP (SP)+,(SP)+ ;POP OFF C & CO-ROUTINE LINKAGE
.CLSS8: TST (SP)+ ;POP OFF FLAG
JMP .RDEF
;ALL CHARS GOTTEN. NUMBER IS IN E,,F
.CLSS9: TST (SP)+ ;BUT SHOULD IT BE NEG?
BGE .CLSSR ;NO
DPNEG E,F
.CLSSR: MOV E,A
MOV F,B
JSR PC,GRBAD
BIS #INUM,C
MOV C,B
JMP .SRDEF
.IFNZ FPPF
;FLOATING POINT CONVERSION ROUTINES
DC CSN2FN,<<.-CNVTOP>/2>
.CSNFN: SPUSH #.CINFN
JMP .CSNIN
DC CIN2FN,<<.-CNVTOP>/2>
.CINFN: MOV #INUM,A
JSR PC,.FLOAD
STCFD FA,-(P)
RFSTR: SPOP A
SPOP B
JSR PC,GRBAD
BIS #FNUM,C
MOV C,B
CLZ
RTS PC
DC CFN2IN,<<.-CNVTOP>/2>
.CFNIN: MOV #FNUM,A
JSR PC,.FLOAD
ADDF #40000,FA
CFCC
BVS .LERR1
BGE 1$
SUBF #40200,FA
1$: STCFI FA,-(P)
BCS .LERR
SPOP A
SPOP B
JSR PC,GRBAD
MOV C,B
BIS #INUM,B
CLZ
RTS PC
.LERR: CMP (P)+,(P)+
.LERR1: SEZ
RTS PC
DC CFN2SN,<<.-CNVTOP>/2>
.CFNSN: JSR PC,.CFNIN
BEQ .LERR1
JMP .CINSN
DC CFN2LS,<<.-CNVTOP>/2>
.CFNLS: SPUSH D
SPUSH E
SPUSH F
MOV #FNUM,A
JSR PC,.FLOAD
JSR PC,.CFNST
JMP .CINL0
.GLOBL FNPDL,SEXP ;057
DC CLS2FN,<<.-CNVTOP>/2>
.CLSFN: CLR FNPDL+2
CLR SEXP
CLR FNPDL
STF FA,FE ;STORE FLOATING REGISTERS
STF FB,FF
CLRF FB
BIT #7777,B ;CAN'T CONVERT EMPTY LSTR
BEQ .FNLR
PUSH D
SPUSH E
SPUSH F
MOV B,GCP1
MOV B,C
CLR E
CLR F
CLR -(P) ;A FLAG FOR THE SIGN OF NUMBER
JSR PC,INSTR1 ;GET FIRST CHAR
BEQ .FERR ;NO CHARS
SETI ;TO PREPARE FOR MOVES FROM REGS TO FLOAT REGS
CMPB D,#53 ;IS CHAR A "+?
BEQ CLSSA
CMPB D,#55 ;IS CHAR A "-?
BNE CLSS3
COM 2(P) ;SET NEGATIVE NUMBER FLAG
CLSSA: JSR PC,@(P)+ ;GET NEXT CHAR
BEQ .FERR ;NO MORE CHAR????
BR CLSS69
CLSS1: JSR PC,@(P)+ ;GET NEXT CHAR
CLSS69: BEQ CLSS9
CLSS3: SUB #60,D ;CONVERT FROM ASCII
BLT CLSS7 ;IT WASN'T A DIGIT
CMPB D,#12
BGE CLSS7 ;IT WASN'T A DIGIT
CLR B
LDCFD #41040,FA ;CONSTANT 10
MULF FA,FB
CFCC
BVS CLSS8
LDCIF D,FD
INC FNPDL+2 ;SET SWITCH
ADDF FD,FB
CFCC
BVS CLSS8 ;OVERFLOWED A FLOATING REGISTER??????!!!
ADD E,F
BR CLSS1 ;GET ANOTHER CHAR
CLSS8: TST (P)+ ;DESTROY CO-ROUTINE LINKAGE
JMP .FERR
CLSS9: CLR B ;NO EXPONENT
JMP OKY
CLSS7: INC FNPDL
CMPB D,#25 ;IS IT "E?
BEQ GTEXP
CMPB D,#36 ;IS IT "N?
BEQ GTNEXP
CMPB D,#177776 ;ITS NOT ".!!??
BNE CLSS8
TST E
BNE CLSS8 ;THERE WERE TWO ".
DEC E
BR CLSS1
.FNLR: LDF FE,FA ;RESTORE REGS
LDF FF,FB
SEZ
RTS PC
FERR2: POPS GCP1
FPOP FB
FPOP FA
.FERR: TST (P)+
LDF FF,FB
LDF FE,FA
SETL
JMP .RDEF
GTNEXP: DEC SEXP ;SET NEG EXPONENT FLAG
GTEXP: SETL
SPOP D ;SAVE CO-ROUTINE LINKAGE
FPUSH FA
FPUSH FB
JSR PC,KL ;GET EXPONENT
BEQ FERR2
POPS GCP1
FPOP FB
FPOP FA
SPUSH A
CLR A
JSR PC,.LOAD ;GET EXPONENT IN A,,B
TST A
BEQ OKAY
SPOP A ;THE EXPONENT WAS TOO TOO LARGE!!!
BR .FERR
OKAY: SPOP A
OKY: TST FNPDL+2
BEQ .FERR
SETL
TST (P)+ ;THE NUMBER IS NEGATIVE?
BGE OKY1
NEGF FB
OKY1: LDCDF #40200,D ;CONSTANT 1
TST SEXP ;GET FINAL EXPONENT
BGE 1$ ;IS EXP NEGATIVE
NEG B
1$: CLR SEXP
ADD B,F
TST F ;GET ABSOLUTE VALUE IN F
BGE LOOP
DEC SEXP
NEG F
LOOP: DEC F ;GET 10 TO THE EXPONENT IN FD
BLT DONEX
MULF FA,FD
CFCC
BVS .FERR+2 ;TO BIG
BR LOOP
DONEX: TST SEXP ;IF EXP IS POSITIVE MULTIPLY BY IT
BLT DIVE ;IF NEG DIVIDE BY IT
MULF FD,FB ;AND PUT RESULT IN FB
CFCC
BVS .FERR+2
BR FIN
DIVE: DIVF FD,FB
FIN: STCFD FB,-(P)
SPOP A ;GET RESULT IN A,,B
SPOP B
JSR PC,GRBAD ;STORE RESULT IN NODE SPACE
BIS #FNUM,C ;PUT POINTER TO DATA IN B
MOV C,B
; TST FNPDL
; BEQ .FERR+2
LDF FF,FB ;RESTORE FLOATING REGS
LDF FE,FA
JMP .SRDEF
KL: SPUSH D ;SHORT FOR KLUDGE.
SPUSH E ;PREPARE TO FAKE OUT .CLSSA
SPUSH F ;IT WILL GET US AN EXPONENT
CLR -(P) ;FAKE A FLAG
SPUSH D ;RESTORE CO-ROUTINE LINKAGE
CLR E
CLR F
PUSHS GCP1
JMP .CLSSA ;GET POINTER TO EXPONENT
;CONVERT FROM FNUM TO SSTR ON P-PDL
.CFNST: SPOP SEXP ;SAVE PC
CLR -(P)
MOV #FNPDL+16,D ;INITIALIZE STACK POINTER
TSTF FA
CFCC
BEQ .CFNZE ;ITS ZERO
BGE .CFNS0
MOVB #'-,-(D) ;PUT IN A MINUS SIGN
NEGF FA ;PROCESS SIGN OF FNUM
.CFNS0: CLR A
LDCFD #40200,FB ;CONSTANT 1
LDCFD #41040,FD ;CONSTANT 10
CMPF FA,FB
CFCC
BLT .CFNS2
.CFNS1: DIVF FD,FA ;NORMALIZE FA
INC A ;DIVIDE UNTIL 0<FA<1
CMPF FA,FB
CFCC
BGE .CFNS1
.CFNS2: MULF FD,FA ;MULTIPLY UNTIL 1<F=FA<10
DEC A
CMPF FA,FB
CFCC
BLT .CFNS2
SPUSH #66152
SPUSH #2657
SPUSH #33675
SPUSH #33006
ADDF (P)+,FA ;ADD .0000005 FOR ROUNDING
CMPF FA,FD ;9.99999999999999 WILL OVERFLOW
CFCC
BLT 1$
DIVF FD,FA
INC A ;MAKE IT 1.000 WHEN IT WAS 10.000
1$: MOV A,FNPDL ;SAVE EXPONENT
MOV #7,B ;COUNTER FOR SEVEN DIGITS
SETI
INC A
BLT 2$ ;ITS LESS THAN .1
CMP #7,A
BLT 2$ ;ITS GREATER THAN 10000000.
INC A
CLR FNPDL
BR .CFNS3
2$: MOV #2,A
.CFNS3: DEC A ;A COUNTS PLACES TO DECIMAL POINT
BNE 1$
MOVB #'.,-(D) ;PUT IN ".
1$: STCFI FA,C ;GET DIGIT
LDCIF C,FB
ADD #'0,C
MOVB C,-(D) ;STACK CHARACTER
SUBF FB,FA ;GET FRACTIONAL PART OF NUMBER
MULF FD,FA
SOB B,.CFNS3
DEC A
BNE 2$
MOVB #'.,-(D)
2$: SETL
CLR A
;FALLS THROUGH
;FALLS IN
.CFNS4: INC A ;COUNT ZEROS POPPED
CMPB #'0,(D)+
BEQ .CFNS4 ;POP INSIGNIFICANT ZEROS
DEC D ;RESET POINTER
MOV FNPDL,B ;RETRIEVE EXPONENT
BEQ .CFNS6 ;NO EXPONENT
BGT .CFNS5
ADD B,A
BGE .CFNS8 ;IT NOW FITS DUE TO POPPED ZEROS
NEG B
MOVB #'N,-(D) ;STACK "N
BR .CFNS5+4
.CFNS5: MOVB #'E,-(D) ;STACK "E
CLR A
MOV D,FNPDL ;SAVE POINTER
JSR PC,.CINST ;REDUCE EXPONENT TO SSTR
SPOP A
SPOP B
MOV FNPDL,D ;RESTORE POINTER
MOVB A,-(D) ;STACK EXPONENT DIGIT
BNE 1$
INC D ;IT WASN'T A DIGIT SO KILL IT
1$: SWAB A
MOVB A,-(D) ;GET OTHER DIGIT
.CFNS6: MOVB (D)+,-(P) ;GET HIGH BYTE
BEQ .CFNS7 ;A ZERO BYTE MEANS ITS DONE
SWAB (P)
MOVB (D)+,(P) ;GET ANOTHER BYTE
BNE .CFNS6 ;ZERO BYTE SIGNALS END
SUB #2,P
.CFNS7: ADD #2,P ;FIX UP STACK POINTER
JMP @SEXP
.CFNZE: SPUSH #"0. ;PUT "0. ON STACK
JMP @SEXP
.CFNS8: ADD D,B ;CREATE POINTER
INC B
MOV B,C ;SAVE IT
.CFNS9: MOVB (D)+,(B)+ ;SHIFT STACK
CMPB #'.,-1(B)
BNE .CFNS9
MOVB (D),-1(B) ;GET LAST DIGIT
MOV FNPDL,A
COM A ;COMPUTE HOW MANY ZEROS ARE TO BE ADDED
.CFN10: MOVB #'0,(B)+
SOB A,.CFN10
MOVB #'.,(B)
MOV C,D ;RESTORE POINTER
BR .CFNS6 ;I HOPE YOUR HAPPY THAT THE EXPONENT IS GONE
.ENDC
.SBTTL GET ARGUMENT ROUTINES
;GET 2 SNUM'S OFF OF S PDL
;RETURN TOP ONE IN A, BOTTOM ONE IN B
G2NARG: JSR PC,G1NARG ;NUMBER IN B
MOV B,A
;GET 1 SNUM OFF OF S PDL
;RETURN IT IN B
G1NARG: POPS B
G1NAR1: MOV A,-(SP) ;ENTER HERE WITH ARG IN B
MOV #SNUM,A
JSR PC,CONVERT
BEQ G1ARG1
MOV (SP)+,A
RTS PC
;GET ONE LIST OR WORD ARG
;SKIP IF WORD
GLWARG: MOV @S,B ;DON'T POP ARG. LEAVE IT GC PROTECTED
GLWAR1: MOV #LSTR,A
JSR PC,CONVERT
BNE GSW2
GSW1: CMP A,#SENT
BNE G1ARG1 ;NOT SENTENCE EITHER
SEZ
GSW2: RTS PC
;GET ONE LIST OR WORD. ERRROR IF EMPTY
GLWANE: MOV @S,B
BIT #7777,B
BEQ G1ARG1
BR GLWAR1
;RETURN ONE NUMERIC ARGUMENT
;CALL WITH SNUM IN B
R1INT: JSR PC,GETINT
R1NARG: JSR PC,.CSNIN ;CONVERT SNUM TO INUM
JMP ORTB
PSHINT: JSR PC,GETINT
;PUSH A NUMBER ONTO THE S-PDL
PSHNUM: JSR PC,.CSNIN
SPUSHS B
RTS PC
.IFZ FPPF
;GET 2 INTEGERS FROM THE S-PDL
G2IARG: JSR PC,G1IARG
MOV B,E
MOV C,F
JSR PC,G1IARG
EXCH B,E
EXCH C,F
ILOAD1: RTS PC
G1ARG1: ERROR+WTAB
.ENDC
;GET 1 INTEGER FROM THE S-PDL
G1IARG: POPS B
SPUSH A ;SAVE A
MOV #INUM,A
JSR PC,CONVERT
BEQ G1ARG1
JSR PC,.LOAD ;INTEGER IN A,,B
MOV B,C
MOV A,B
SPOP A
RTS PC
.IFZ FPPF
;RETURN 1 INTEGER FROM B,,C
R1I.BC: MOV B,A
MOV C,B
BR R1I.N
;;RETURN 1 INTEGER FROM E,,F
R1I.EF: MOV E,A
MOV F,B
R1I.N: JSR PC,GRBAD
BIS #INUM,C
JMP ORTC
.ENDC
.IFNZ FPPF
;ROUTINES TO LOAD FLOATING REGS FROM NODESPACE
G2ARG: MOV #INUM,F
JSR PC,G1NUM ;GET 1 INTO FA
BEQ G1ARG1
LDD FA,FC
JSR PC,G1NUM ;GET ANOTHER
BEQ G1ARG1
LDD FA,FB
LDD FC,FA ;SWITCH THEM
RTS PC ;F WILL CONTAIN TYPE EXPECTED OF
;ARITHMETIC RESULT
;LOAD ONE ARG INTO FA AND ERROR+WTA
G1ARG: JSR PC,G1NUM
BNE ILOAD1
G1ARG1: ERROR+WTAB
;LOAD ONE ARG INTO FA AND CLZ
G1NUM: POPS B
G1NUMS: MOV B,A ;IS IT ALREADY AN FNUM?
BIC #7777,A
CMP #FNUM,A
BEQ G1FAG
MOV #INUM,A
JSR PC,CONVERT ;TRY TO GET AN INUM
BNE .FLOAD
MOV #FNUM,A
JSR PC,CONVERT ;TRY TO GET A FNUM
BEQ ILOAD1
G1FAG: MOV A,F ;SET F TO SHOW FNUM
.FLOAD: BIC #170000,B
ASL B
ASL B
ADD #NODESP,B
CMP #INUM,A
BEQ .ILOAD ;LOAD AN INUM?
LDCFD (B),FA ;LOAD FNUM
CLZ
RTS PC
.ILOAD: LDCIF (B),FA ;LOAD INUM
CLZ
ILOAD1: RTS PC
.ENDC
;GET 1 SNAP
; RETURN POINTER TO SNAP IN D, DELTA X IN E, DELTA Y IN F
G1SNAP: MOV @S,C ;POINTER TO ARG
BIT #7777,C ;IS IT EMPTY?
BEQ ILOAD1 ;YES. RETURN WITHOUT SKIPPING
;LOAD 3 NUMBERS
; GROVEL DOWN A LIST OF NUMBERS RETURNING 3 NUMBERS IN D,E,F
; CALL WITH C POINTING TO LIST
; IF LIST CONTAINS 1)NON-NUMBERS OR 2)MORE THAN 3 ELEMENTS,
; THEN ERROR+WTA
LD3NUM: PUSH A
SPUSH B
SPUSH C
MOV #7777,D ;AN OFT USED CONSTANT
MOV #3,F ;COUNTER
LDN.L: BIT D,C ;IS THERE MORE LIST?
BEQ LDN.ER ;ERROR
JSR PC,.LOADC ;LOAD A WITH NEXT ELEMENT
MOV A,C
.IFNZ FPPF
CMP #3,F
BGT LDN.E
.ENDC
MOV #SNUM,A
JSR PC,CONVERT
BEQ LDN.ER
LDN.E: SPUSH B ;PUSH THIS ELEMENT
SOB F,LDN.L
BIT D,C ;IS THE LIST FINISHED?
BNE LDN.ER ;NO. ERROR
JMP SRETF ;SKIP RETURN AND RESTORE ALL AC'S!
LDN.ER: ERROR+WTA
.SBTTL EVAL
EVAL: JSR PC,GNT ;GET NEXT TOKEN, RETURNED IN A
.IIF NZ DEBUGR, JSR PC,STRACE ;CHECK FOR SYSTEM TRACE
BIC #DPQF+CPTBF,FLAGS2 ;DON'T PRINT QUOTE, CHANGE % TO BLANK
BIC #7777,A
CMP A,#UFUN ;USER FUNCTION?
BLOS EVFUN
CMP A,#UVAR ;USER VARIABLE?
BEQ EVVAR
CMP A,#SSTR
BHI EVWHA1
EVWHAT: .BUG.
EVWHA1: CMP A,#ATOM
BEQ EVATM
CMP A,#SNUM ;INTEGER?
BEQ EVWHAT
.IIF Z FPPF, CMP A,#LSTR
.IIF NZ FPPF, CMP A,#FNUM
BLOS EVCON
CMP A,#LIST
BNE EVWHAT
EVCON:
EVATM:
PUSHS CT ;SAVE ON S-PDL FOR OUTPUT
BR EVI
EVVAR: BIC #170000,B
BIS #ATOM,B
MOV B,D ;SAVE UOE PTR FOR ERROR
JSR PC,.BINDL
BEQ EVVAR2 ;NO BINDING FOUND
TST B ;NIL?
BNE EVVAR1 ;NO, GOOD
MOV D,B
EVVAR2: ERROR+HNV ;... HAS NO VALUE
EVVAR1: PUSHS B ;SAVE IT FOR OUTPUT
EVI: JSR PC,GNT ;ABOUT TO OUTPUT A VALUE.
;BEFORE WE DO, CHECK TO SEE IF
;NEXT TOKEN IS INFIX WHICH SHOULD GOBBLE IT.
BIC #7777,A ;IS NEXT TOKEN INFIX?
CMP #INFIX,A
BEQ CKPRCD ;YES
EVI1: BIS #RTF,FLAGS ;SET REPEAT TOKEN FLAG
BIC #CRF,FLAGS ;CLEAR CARRIAGE RETURN TOKEN FLAG
CLZ
RTS PC
.GLOBL $BKAR,CO,COF,NOR ;066
CKPRCD: TST CO ;COMPARE PRECEDENCE
BEQ EVI2
MOV CT,A
BIC #170000,A ;CLEAR OUT THE TYPE (FOR INFIX TYPES)
ASL A
MOV SOBLST(A),A ;SYSTEM OBLIST ELEMENT (NEXT OPER.)
BIC #7777,A
MOV COF,B ;CURRENT OPERATOR FLAG
BIC #7777,B
CMP A,B ;IS PRECD OF CO >= PRECD NEXT OPER
BLO EVI1 ;YES, > - GIVE OUTPUT TO CO
BEQ EVI4 ;YES, = - CHECK FOR _
;NO - NEXT TOKEN SHOULD GOBBLE THIS OUTPUT
EVI2:
.IIF NZ DEBUGR, JSR PC,STRACE
EVI3: PUSH CO
SPUSH NOR ;NO. OF OPERANDS STILL NEEDED
MOV CT,CO
MOV CO,A ;GET FLAGS
BIC #170000,A ;CLEAR OUT THE INFIX TYPE
ASL A
MOV SOBLST(A),COF ;SET CURRENT OPERATOR FLAG
MOV #1,NOR
JMP EVW ;CALLS EVAL
EVI4: CMP #INFIX+$BKAR,CT ;PRECD ARE = - IF _ DO RIGHT ONE FIRST
BEQ EVI2 ;IT IS _
BR EVI1
.GLOBL $DO,$LLPAR,EDTIF2,HNM,PREPRI,UELX ;067
EVFUN: BIT #CRF,FLAGS ;CT IS A FUNCTION
BEQ 1$
ERROR+UELX ;UNEXPECTED END OF LINE
1$: CMP #$LPAR,CT ;IS NEXT TOKEN A LEFT PAREN?
BNE EVF1
TST CO ;NEXT OPERATOR?
BEQ EVF11 ;NOTHING THERE
.IFNZ ENG
CMP #$DO,CO ;IS NEXT OPERATOR A RUN COMMAND?
BEQ EVF11
.ENDC
.IFNZ FR
CMP #$EXECUT,CO
BEQ EVF11
.ENDC
CMP #$LLPAR,CO
BNE EVF1
EVF11: MOV #$LLPAR,CT ;INSERT PARENS.FOR PARSE
EVF1: PUSH CO
SPUSH NOR ;NO. OF ARGS NEEDED FOR CO'S EXECUTION
CMP #$LLPAR,CO ;IF CO IS !(, PUSH IFLEV INSTEAD OF NOR
BNE EVF13
MOV IFLEV,(P)
CLR IFLEV
EVF13: MOV CT,CO
CLR EDTIF2
EVF2: CMP A,#UFUN ;IS POPPED OPER. A USER FUNCTION?
BLO MFUN ;NO, MACHINE
MOV #<PREPRI_13.>,COF ;SET PRECD TO PREPRI
JSR PC,GNASN ;GET NO. OF ARGS IN B
BNE 1$ ;FOUND A FUNCTION BINDING
ERROR+HNM ;... HAS NO MEANING
1$: MOVB B,B ;CLEAR ANY LEFT HALF FLAGS
MOV B,NOR
BEQ EVXP ;NO ARGUMENTS, THEN JUST EVALUATE IT
JMP EVL1
EVXP:
.IIF NZ DEBUGR, JSR PC,STRACS ;NO MORE, SPACE AND CHECK FOR SYSTEM TRACE
JSR PC,PEVAL ;SET TO EVALUATE THIS USER PROCEDURE
BEQ XNORT ;PEVAL DOES SEZ IF THERE IS NO OUTPUT
JMP XORT ;DOES CLZ IF THERE IS
.GLOBL INF1,LO,VNAF ;068
MFUN: MOV CO,A ;GET FLAGS FOR THIS MACHINE PROCEDURE
BIC #170000,A ;CLEAR THE INFIX TYPE
ASL A
MOV SOBLST(A),A
MOV A,COF
SWAB A
BIC #ARGMSK,A ;FIND NO. OF ARGS. NECESSARY
MOV A,NOR
BNE EVS ;IS NO. ARGS = 0? (BRANCH IF NO)
BIT #PTLPF,FLAGS ;PREVIOUS TOKEN LP?
BEQ EVXM ;NO, AND NO ARGS NEEDED, EXECUTE
BIT #VNAF,COF ;VARIABLE?
BNE EVL ;YES, GO MAYBE GOBBLE ARG(S)
EVXM: JMP MEVAL ;YES. EXECUTE THIS MACHINE PROCEDURE
XNORT: BIC #EDTIF,FLAGS
TST EDTIF2
BEQ NORT0
BIS #EDTIF,FLAGS
NORT0: MOV #EVDNO,A ;SET RETURN TO INDICATE NO OUTPUT
NORT1:
MOV CO,LO
POP NOR
SPOP B
MOV B,CO
CMP #$LLPAR,B ;IF POPPED OPER IS !(, IFLEV_NOR, NOR_1
BNE NORT3
MOV NOR,IFLEV
MOV #1,NOR
NORT3: CLR COF
TST B
BEQ NORT2 ;NO MORE OPERATORS
BIT #160000,CO ;IS IT A UFUN
BNE NORT2 ;YES
BIC #170000,B ;CLEAR THE INFIX TYPE
ASL B ;NO, MUST BE A PRIMITIVE. GET OFFSET IN BYTES
MOV SOBLST(B),COF
NORT2: JMP (A) ;RETURN DEPENDS ON WHETHER OUTPUT EXISTS
EVDNO: SEZ
RTS PC
EVS: BIT COF,#INFIX ;IS CO INFIX OP
BEQ EVL ;NO
JSR PC,CKUI ;CHECK FOR VALID UNARY INFIX +,-
BNE EVW
ERROR+INF1 ;INFIX IN WRONG PLACE
PROC: MOV @S,B ;THE WORD
BIT #7777,B ;IS IT THE EMPTY WORD
BNE 1$
ERROR+WTA
1$: JSR PC,GUOEB ;PEVAL INVOKED VIA "#"
BEQ PROC1
MOV B,(P) ;OLD RETURN - POPPED LATER
JSR PC,.BINDF ;IS A PROC DEFINED
BEQ PROC3 ;NO
MOV #UFUN,CO ;YES
MOV (P),B
PROC2: CLR TOPS
MOV B,CO
SPOP B ;GET P BACK IN PHASE
JMP EVF2
PROC3: JSR PC,.LOAD ;GET PNAME FOR UOBSCH
PROC1: MOV B,TOPS
MOV #SFUN,A
JSR PC,UOBSCH ;MAKE SURE CO EXISTS
BNE 1$
ERROR+HNM ;HAS NO MEANING
1$: MOV A,CO
BR PROC2
.GLOBL ERP,NIP,NOU,TIP,TMAP ;069
EVL: BIT #PTLPF,FLAGS ;WAS PREVIOUS TOKEN A LEFT PAREN
BEQ EVL1 ;NO
BIT #VNAF,COF ;DOES CO USE VARIABLE NO. OF ARGS.?
BEQ EVL1 ;NO
CLR NOR
BR EVW9
EVL1: JSR PC,GNT
EVW1: BIS #RTF,FLAGS ;SET REPEAT TOKEN FLAG
BIC #CRF,FLAGS
EVW: JSR PC,EVAL ;EVALUATE THIS ARGUMENT
BEQ EVW2 ;NO OUTPUT FROM EVAL
DEC NOR
BEQ EVX ;WHEN NOR = 0, WE'VE ENUF INPUTS
EVW9: JSR PC,GNT
TST NOR ;IF NOR < 0 AND NEXT TOKEN IS ")" THEN THE ")"
BGT EVW1 ;TERMINATES THE ARG SCAN FOR THE CO
CMP #$RPAR,CT
BNE EVW1 ;NO
BIS #RTF,FLAGS
BIC #CRF,FLAGS
NEG NOR
CMP #MAXARG,NOR
BGE MEVAL ;EXECUTE MACHINE PROC.
ERROR+TMAP ;TOO MANY ARGS COMMAND/OPERATION
EVX: BIT #160000,CO ;IS IT A MACHINE PROCEDURE
BEQ 1$
JMP EVXP ;NO
1$: BIT #VNAF,COF ;MACHINE PROC NOW HAS ITS "STD" NO. OF ARGS.
;IF IT CAN TAKE A VARIABLE NO., THEN THE "STD" NO. HAS
;BE PUSHED ON P
BEQ MEVAL ;IT DOESN'T- GO EVALUATE IT
MOV COF,A
SWAB A
BIC #ARGMSK,A
MOV A,NOR
BR MEVAL
EVW2:
CMP #$LLPAR,CO ;EVAL SHOULD OUTPUT WHEN NOT AT TOP LEVEL
BEQ EVW ;EXCEPT WHEN CO IS LLPAR
ERROR+NOU ;WHAT, NO OUTPUT??!!
LLPAR:
LPAR: JSR PC,GNT
CMP #$RPAR,CT
BEQ LPAR1
ERROR+TIP ;TOO MUCH INSIDE PARENS
LPAR1: CLZ
RTS PC
RPAR: BIT #PTLPF,FLAGS
BEQ 1$
ERROR+NIP ;NOTHING INSIDE PARENS
1$: CMP 4(P),#$LLPAR ;IS PENDING COMMAND !(
BNE RPAR1
RPAR2: POP A
MOV (P),IFLEV
CMP (P)+,(P)+ ;POP !( OFF THE STACK
MOV A,(P) ;CRETINOUS NON-LOCAL RETURN
SEZ
RTS PC
RPAR1: ERROR+ERP ;EXTRA RIGHT PAREN
.GLOBL $MINUS,$PLUS,$UMINS,$UPLUS ;070
CKUI: PUSH A
MOV CO,A
BIC #170000,A ;CLEAR THE INFIX TYPE
CMP A,#$PLUS ;+
BNE CKUI1
MOV #$UPLUS,A
CKUI0:
MOV A,CO
ASL A
MOV SOBLST(A),COF
MOV #1,NOR
JMP SRETA
CKUI1: CMP A,#$MINUS ;-
BNE CKUI2
MOV #$UMINS,A
BR CKUI0
CKUI2: POP A
RTS PC
MEVAL:
.IIF NZ DEBUGR, JSR PC,STRACS
MOV CO,A
BIC #170000,A ;CLEAR OUT THE INFIX TYPE
CLR NBKTS
MOV NOR,D ;ONLY NEEDED FOR MULTIPLE ARG THINGS, BUT IT WON'T HURT...
ASL A
.IIF NZ METERS, MOV #MTPRIM,METERP ;IN A PRIMITIVE
JSR PC,@2+SOBLST(A) ;JMP ADDR IS IN 2ND WORD
BNE XORT ;PROCEDUE OUTPUTS
LDFPS #40300
.IIF NZ METERS, MOV #MTEVAL,METERP ;IN THE EVALUATOR
JMP XNORT ;NO OUTPUT
XORT: LDFPS #40300
MOV #EVI,A
.IIF NZ METERS, MOV #MTEVAL,METERP ;IN THE EVALUATOR
JMP NORT1
ORTNA: MOV A,@S
BR SRET
ORTNB: MOV B,@S
BR SRET
ORTNC: MOV C,@S
BR SRET
ORTND: MOV D,@S
BR SRET
ORTNE: MOV E,@S
BR SRET
ORTNF: MOV F,@S
BR SRET
ORTNP: MOV (SP)+,@S
BR SRET
ORTA: PUSHS A
BR SRET
ORTB: PUSHS B
BR SRET
ORTC: PUSHS C
BR SRET
ORTD: PUSHS D
BR SRET
ORTE: PUSHS E
BR SRET
ORTF: PUSHS F
BR SRET
DC ORTP,.
ORTSP: PUSHS (SP)+
RETF: POP F
BR RETE1
RETE: POP E
BR RETD1
RETD: POP D
BR RETC1
RETC: POP C
BR RETB1
RETB: POP B
BR RETA1
RETA: POP A
SEZ
RTS PC
RETF1: SPOP F
RETE1: SPOP E
RETD1: SPOP D
RETC1: SPOP C
RETB1: SPOP B
RETA1: SPOP A
RET: SEZ
RTS PC
SRETF: POP F
BR SRETE1
SRETE: POP E
BR SRETD1
SRETD: POP D
BR SRETC1
SRETC: POP C
BR SRETB1
SRETA: POP A ;POP A THEN DO CLZ RETURN
BR SRET
SRETE1: SPOP E
SRETD1: SPOP D
SRETC1: SPOP C
SRETB1: SPOP B
SRETA1: SPOP A ;POP A THEN DO CLZ RETURN
SRET: CLZ
RTS PC
.SBTTL PROCEDURE EVALUATOR
.GLOBL CPP,SPUSHL,TF7 ;072
.GLOBL $COMT,$LOCAL,$USING,$AVEC ;073
.GLOBL CPBND,CPDLP,PROEND,PROSTK,WDW ;074
.GLOBL PBASE,SPSWPO ;075
PEVAL: JSR PC,CKSTG ;CHECK STORAGE
MOV CO,B ;FIRST CHECK IF THE PROC IS THERE
JSR PC,.BINDF ;GET BINDING
BNE 1$
ERROR+HNM ;PROCEDURE HAS NO MEANING
1$: JSR PC,SAVEVL ;SAVE ALL PROCEDURE INFORMATION
MOV B,C ;SAVE POINTER TO THE ARRAY WE WILL EVAL
MOV CO,B ;GET BACK POINTER TO THE ATOM
MOV B,CPP ;SET UP POINTER TO PROCEDURE NAME
JSR PC,GNASN ;GET THE NUMBER OF ARGMENTS AND FLAGS IN B
MOV B,FLAGS
MOVB B,B
SPUSH B ;PUSH # ARGS
MOV #TRRTS,TF7 ;SET TRACE DISP
BIC #-<TPTF+TPSF>-1,FLAGS ;CLEAR ALL BUT TRACE AND STEP FLAGS
.IF NZ DEBUGR
BNE PEV3
BIT #TRACEF,FLAGS2 ;IS TRACE SET?
.ENDC
BEQ PEV6 ;NO
PEV3:
.IIF NZ DEBUGR, BIS #TPTF,FLAGS ;IT REALLY IS TRACED
MOV #TINPUT,TF7
MOV CO,B ;SET UP B TO POINT TO THE PROCEDURE
INC FUNLEV
JSR PC,TINDNT ;SET SPACING ACCORDING TO FUNCTION LEVEL
DEC FUNLEV
STLANC
ENGINS <JSR PC,PPNAME> ;PRINT PROCEDURE NAME
ENGINS <PRTXT ^\ STARTS. \>
ENDENG
FRINS <JSR PC,PPNAME>
FRINS <PRTXT ^\ COMMENCE. \>
ENDLAN
MOV (P),B ;# OF ARGS
PEV6: SPUSH C ;SAVE FOR BELOW (POINTS TO LASTLINEPTR)
;SAVE FOR BELOW POINTS TO START OF THE ARRAY
MOV B,D ;NO. OF ARGS
ADD #HEADER,C ;POINT TO THE START OF THE ARRAY DATA
SPUSH C ;PUSH POINTER TO THE ARGUMENTS LINE
ASH #2,B ;GET THE NUMBER OF BYTES WE WILL NEED ON THE STACK
NEG B
ADD S,B ;GET THE ULTIMATE VALUE OF S
CMP SPUSHL,B ;ENOUGH ROOM ON S-PDL?
BLOS 2$ ;OK
JSR PC,SPSWPO ;SWAP OUT S-PDL
2$: MOV D,B ;# OF ARGS
ASL B ;MULTIPLY BY TWO FOR OFFSET
MOV S,D
MOV D,E
SUB B,E
MOV E,S
;DROPS INTO NEXT PAGE
;DROPPED IN FROM ABOVE
ASR B
BEQ 3$
1$: MOV (D)+,(E)+ ;GET ARGS ON TOP OF STACK
SOB B,1$
3$: MOV (P),A ;GET SAVED LLP PTR
MOV A,F ;POINTER TO THE END OF THIS LINE
ADD (A),F ;POINT TO THE START OF THE NEXT LINE
ADD #2,F ;BECAUSE THE NUMBER OF VARIABLES IS ON THIS LINE
ADD #4,A ;MAKE A POINT TO THE FIRST VARIABLE
MOV A,(P) ;AND PUT IT BACK
PEV1: CMP A,F ;ARE WE AT END?
BEQ PEV11 ;YUP, GIVE UP
MOV (A)+,B ;GET THE NEXT ARGUMENT
MOV A,(P) ;PTR. TO NEXT NODE
CMP #$COMT,B ;IS CURRENT NODE A COMMENT?
BNE 1$
JSR PC,PEVCOM ;GO PAST COMMENT
BR PEV1 ;GET A REAL THING
1$: CMP #$LOCAL,B ;IS CURRENT NODE LOCAL?
BEQ PEVLOC ;GO GOBBLE LOCALS
STLANC
ENGINS < CMP #$USING,B ;USING?>
ENGINS < BEQ PEVLOC ;SAME>
ENDENG
FRINS < CMP #$AVEC,B ;AVEC?>
FRINS < BEQ PEVLOC ;TREAT AS WITH LOCAL>
ENDLAN
BR PEV10
PEVCOM: CMP A,F ;ARE WE POINTING TO THE NEXT LINE?
BEQ PEVCO1
MOV (A)+,B ;GET THE NEXT TOKEN ON THIS LINE
CMP #$COMT,B
BNE PEVCOM
PEVCO1: RTS PC
PEV10: JSR PC,@TF7
JSR PC,SAVVAR ;SAVE THIS VARIABLE BINDING
MOV (P),A
CMP A,F ;ARE WE AT THE END OF THE TITLE LINE?
BEQ PEV11
BR PEV1 ;GO DO NEXT ARG
TINPUT:
STLANC
ENGINS <PRTXT ^\ITS INPUTS ARE: \>
ENDENG
FRINS <PRTXT ^/LES INPUTS SONT: />
ENDLAN
MOV #CINPUT,TF7
BR PINPUT
CINPUT: PRTXT ^\, \
PINPUT: SAVE <A,B,D>
MOV -2(E),B ;TOP ARGUMENT
MOV B,A
INC NBKTS
JSR PC,PRTAB ;PRINT TOKEN IN A,,B
DEC NBKTS
REST <D,B,A>
TRRTS: RTS PC
PEVLOC: CMP A,F
BEQ PEV11
MOV (A)+,B
MOV A,(P)
CMP #$COMT,B ;COMMENT?
BNE 1$
JSR PC,PEVCOM ;GO PAST IT
BR PEVLOC
1$: JSR PC,LOCVAR
INC 4(P) ;CHANGE NUMBER OF ARGS
MOV (P),A
BR PEVLOC
PEV11: SPOP C ;USED TITLE LINE POINTER
PEV2:
SPOP C ;PTR TO LLP THAT WAS PUSHED WAY ABOVE
;POINTER TO THE START OF THE ARRAY
MOV (C),CPBND ;SET UP POINTER TO THE BINDING NODE
INC PROSTK(C) ;INCREMENT THE REFERENCE COUNT FOR THIS PROCEDURE
MOV C,F ;COPY IT
ADD #HEADER,F ;POINT TO THE PROCEDURE START
ADD (F)+,F ;POINT TO THE FIRST LINE
SUB C,F ;MAKE IT RELATIVE TO THE START OF THE PROCEDURE ARRAY
MOV F,CTP ;F POINTS TO THE FIRST EXECUTABLE LINE OF THE PROCEDURE
CMP F,PROEND(C) ;IS IT = TO THE END OF THE PROC?
BNE 1$ ;NO
CLR CTP ;OH WELL, MAKE IT STOP AT EVAL LEVEL
1$:
CMP #TRRTS,TF7
BEQ PEV2B
PEV2A: PRCR
PEV2B: JSR PC,SAVPPS ;SAVE PDL PTRS
BIS #1,CPDLP ;INDICATES PROC PUSH AS OPPOSED TO A LOCAL PUSH
CLR CPLN
CLR CO
CLR IFLEV
INC FUNLEV
PMLOOP: JSR PC,GETLIN
JSR PC,EVLINE
BEQ PMWDW
BR PMLOOP ;LOOP BACK
PMWDW: ERROR+WDW ;WHAT SHOULD I DOO WITH (S)
GETLIN: MOV CTP,A ;POINTER TO END OF PREVIOUS LINE
BEQ ENDPRO ;THE END OF THIS PROCEDURE
MOV A,C
MOV @CPBND,F ;GET POINTER TO START OF ARRAY
ADD F,C ;MAKE IT AN ABSOLUTE POINTER
MOV 2(C),CPLN ;GET THE LINE NUMBER
CMP A,PROEND(F) ;ARE WE AT THE END?
BEQ ENDPRO
BHI GSTBUG
MOV CPBND,PBASE ;MAKE PBASE POINT TO THE PROCEDURE IN QUESTION
BIT #TPSF,FLAGS ;PROCEDURES STEPPED?
BEQ 2$ ;NOPE
JSR PC,LINSTP ;PRINT THE LINE, AND WAIT FOR CR.
2$:
.IF NZ DEBUGR
BIT #TRACEF,FLAGS2 ;ARE WE TRACED
BEQ GSTDON ;NO, WE ARE DONE
SPUSH A ;SAVE THE POINTER TO THE LINE
CPRTXT ^\ #\
MOV CPP,B
JSR PC,PPNAME ;PRINT PNAME
PRTXT ^\ LINE \
MOV CPLN,A
JSR PC,PRDN
PRCR
SPOP F ;GET BACK POINTER
JSR PC,PRLN
PRCR
.ENDC
GSTDON: RTS PC
GSTBUG: .BUG. ;PROCEDURE SCREWED
ENDPRO: TST (P)+ ;POP OFF THE RETURN ADDRESS
JMP PSTOP ;STOP THIS PROCEDURE
.GLOBL .SPACE,CSPDLP,IP,PRBAO,SPRBAO ;076
SAVVAR: ;SAVE IN (D) VARIABLE BINDING OF UOE PT'ED TO BY B
;GIVE IT NEW VALUE WHICH IS AT (E)
;USES A,C. TOPS MUST BE 0
;BOTH D AND E ARE -()ED
MOV B,-(D) ;SAVE UOE PTR
MOV #VBIND,A ;THIS WILL CHECK SPDL THINGS--
;NOP IT IF IT SEEMS TO CAUSE TROUBLE. RWW
JSR PC,.BINDL ;NOW GET VARIB. BINDING
BEQ SAVV2 ;NOT THERE
SAVV1: MOV -(E),A ;GET NEW VALUE PTR
MOV B,-(D) ;SAVE OLD VALUE PO[NTER
MOV A,B
JSR PC,.LDP1
BIC #100000,A ;MAKE SURE BINDING NODE SAYS "VBIND"
JSR PC,.STORE ;STORE NEW BINDING AWAY
RTS PC
SAVV3: TST -(E)
CLR -(D) ;THERE IS NO OLD VALUE POINTER
RTS PC
SAVV2: TST -2(E)
BEQ SAVV3 ;IF NEW VALUE = 0, DON'T BOTHER TO CREATE CELL
MOV #VBIND,A
CLR B
JSR PC,GRBAD1
BR SAVV1
SAVPPS: POP F ;SAVE P AND S PDL PTRS
SPUSH CSPDLP
MOV IS,A ;COMPUTE RELATIVE S PDL PTR
SUB S,A ;CURRENT TOP OF S-PDL
ADD SPRBAO,A ;# OF PDL BLOCKS SWAPPED OUT
MOV A,CSPDLP
SPUSH CPDLP
MOV IP,A ;COMPUTE RELATIVE P PDL PTR
SUB P,A
ADD PRBAO,A
MOV A,CPDLP
JMP (F)
TINDNT: PUSH A ;TRACE INDENT
MOV FUNLEV,A
TIND2: DEC A
BGT TIND1
JMP RETA
TIND1: SPACE
BR TIND2
LOCAL: JSR PC,GUOEB ;GET UOE PTR FROM S
LOC9: MOV IS,F ;MOVE STUFF FROM S TO P PDLS
SUB S,F
ADD SPRBAO,F
MOV CSPDLP,D
BIC #1,D
SUB D,F
ASR F
MOV F,A
BLE LOC2
LOC1: POPS D
PUSH D
DEC A
BGT LOC1
LOC2: JSR PC,LOCVAR ;STORE AWAY POINTER AND OLD VALUE
MOV F,A ;NOW RETURN STUFF FROM P TO S
BLE LOC4
LOC3: POP D
PUSHS D
DEC A
BGT LOC3
LOC4: MOV IP,A ;NOW MOVE STUFF FROM P TO S
SUB P,A
ADD PRBAO,A
MOV CPDLP,D
BIC #1,D
SUB D,A
ASR A
MOV A,F
BLE LOC6
LOC5: POP D
PUSHS D
DEC A
BGT LOC5
LOC6: PUSH #1 ;PUSH GOODIES ON P
SPUSH CSPDLP
SPUSH CPDLP
BIC #1,CPDLP ;INDICATE LOCAL PUSH
BIC #1,CSPDLP
ADD #4,CSPDLP
ADD #6,CPDLP
MOV F,A
BLE LOC8
LOC7: POPS D ;NOW RETURN STUFF TO P
PUSH D
DEC A
BGT LOC7
LOC8: SEZ
RTS PC
LOCVAR: MOV S,D ;GET THE ULTIMATE VALUE OF S
SUB #14,D ;ROOM FOR THE STUFF TO PUSH & PARANOIA
CMP SPUSHL,D ;ENOUGH ROOM ON S-PDL?
BLOS 2$ ;OK
JSR PC,SPSWPO ;SWAP OUT S-PDL
2$: MOV S,D ;NOW STORE AWAY PTR & OLD VALUE
SPUSHS #0
MOV S,E
SPUSHS #0
JMP SAVVAR
.SBTTL PROC EVAL - "OUTPUT" "STOP"
.GLOBL DOFRET,OIP,PSTOPR ;078
.GLOBL ILINEL,PROTYP,TF3 ;079
OIPTST: TST FUNLEV ;IN A PROCEDURE
BGT 1$ ;YES
2$: ERROR+OIP ;ONLY IN A PROCDURE
1$: BIT #BRKF,FLAGS ;ARE WE IN A BREAK LOOP
BNE 2$
RTS PC
OUTPUT: JSR PC,OIPTST
OUTPU2: MOV #SRET,PSTOPR ;SEZ WHEN WE RETURN
BR PSTOP1 ;AND STOP THIS PROCEDURE
STOP:
PSTOP: JSR PC,OIPTST
MOV #RET,PSTOPR ;CLZ WHEN WE RETURN
CLR TOPS1 ;JUST RANDOM
PSTOP1: MOV #POPFRM,DOFRET ;JUST POP THE DO FRAME
BIT #DORF,FLAGS ;IS IT A DO FRAME?
BNE POPFRM ;IGNORE THE TRACE
BIT #TPTF!TPSF,FLAGS ;PROCEDURE TRACED?
BEQ POPFRM ;NO, JUST IGNORE
PSTOP3: JSR PC,TINDNT ;INDENT THE RIGHT AMOUNT
;HERE PRINT MESSAGE
MOV CPP,B ;GET POINTER TO PROCEDURE NAME
JSR PC,PPNAME ;AND PRINT IT
CMP #SRET,PSTOPR ;OUTPUTTING?
BNE PSTOP5 ;NO, PRINT JUST "STOPS"
MOV @S,B ;GET THE OUTPUT
PRTXT ^\ OUTPUTS \ ;PRINT "OUTPUTS"
INC NBKTS ;PRINT BRACKETS AROUND THE OUTPUT
JSR PC,PNODAB ;AND PRINT THE OUTPUT
DEC NBKTS ;AND RESET FLAG
BR PSTOP8 ;PRINT CR AND CONTINUE
PSTOP5:
STLANC
ENGINS <PRTXT ^\ STOPS. \>
ENDENG
FRINS <PRTXT ^\ STOPPE. \>
ENDLAN
PSTOP8: PRCR ;PRINT CR.
;FALLS THROUGH, OR BRANCES INTO NEXT PAGE
;IS BRANCHED INTO, AND FALLEN INTO FROM PREVIOUS PAGE
;HERE IS AN ENTRY POINT FOR RESTORING THE VARIABLES FOR A FRAME
;IF OUTPUTTING, EXPECTS PSTOPR TO BE SRET, AND OUTPUT ON STACK
;POPVAR IGNORES OUPUT, AND JUST POPS THE FRAME
POPFRM: CMP #SRET,PSTOPR ;OUTPUTTING?
BNE POPVAR ;NO
POPS TOPS1 ;PUT OUTPUT INTO TOPS1
POPVAR: JSR PC,RESPPS ;RESTORE THE PDLS
SPOP D ;GET THE NUMBER OF ARGUMENTS
BEQ PSTOP6 ;NONE, DONT BOTHER REBINDING
PSTOP4: POPS TOPS ;GET THE OLD VARIABLE BINDING
SPOPS B ;GETH THE UOE POINTER
MOV #VBIND,A ;MAKE A VARIABLE BINDING
TST TOPS ;IS IT GOING TO BE BOUND?
BEQ PVUNBN ;THEN UNBIND IT
JSR PC,.BIND ;GET A POINTER TO THE BINDING
PSTOP7: SOB D,PSTOP4 ;DO IT FOR ALL THE VARIABLES
BR PSTOP6 ;DONE WITH THIS FRAME
PVUNBN: JSR PC,.UNBND ;UNBIND IT
SOB D,PSTOP4 ;AND RETURN TO NEXT VARIABLE
PSTOP6: TST TF3 ;WAS IT A LOCAL PUSH
BEQ POPVAR ;YES, CONTINUE POPPING UNTIL WE GET TO SOMETHING
;WITH SOME MEAT ON IT
BIT #DORF,FLAGS ;IS IT A DO FRAME?
BNE STOPDO ;STOP A DO FRAME
BIT #ERRF,FLAGS ;ERROR FRAME?
BNE 1$ ;YES, JUST RETURN
DEC FUNLEV ;ONE LESS FUNCTION LEVEL
MOV @CPBND,E ;GET POINTER TO THE ARRAY WE ARE LEAVING IN E
DEC PROSTK(E) ;DECREMENT THE REFERENCE COUNT
BLT PRCNTB ;ERROR IF LESS THAN 0
BGT 1$ ;STILL REFENCED ON THE STACK
TST PROTYP(E) ;HAS IT BEEN DELETED?
BPL 1$ ;NO
MOV E,B ;COPY POINTER TO THE ARRAY
JSR PC,DELPRO ;AND DELETE IT
1$: JSR PC,RESEVL ;GET BACK EVAL
MOV B,FLAGS ;AND RESTORE THE FLAGS
JSR PC,POUTPU ;AND RESTACK OUTPUT IF NEEDED
JMP @PSTOPR ;SAY WE HAVE STOPPED
STOPDO: SPOPS A ;GET BACK POINTER TO THE ILINE
MOV A,ILINEL ;GC PROTECT IT
JSR PC,WRTLIN ;AND WRITE IT AWAY
JSR PC,RESEVL ;RETORE EVAL
MOV B,FLAGS ;RESTORE THEM
JSR PC,POUTPU ;OUTPUT IF WE SHOULD
JMP @DOFRET ;AND NOW WE HAVE CLEANED UP
POUTPU: CMP #SRET,PSTOPR ;OUTPUTTING?
BNE POUTP1 ;NO
PUSHS TOPS1 ;PUSH OUTPUT ON THE STACK
CLR TOPS1 ;AND FLUSH THE GC-PROTECTION
POUTP1: RTS PC
PRCNTB: .BUG. ;REFENCE COUNT WAS NEGATIVE
RESPPS: SPOP E ;RESTORE P AND S PDLS
MOV CPDLP,A
CLR TF3
CLR TF7
BIT #1,A
BEQ 1$
MOV PC,TF3
1$: BIC #1,A ;ALWAYS EVEN
JSR PC,PPTA ;POP P TO (A)
POP CPDLP ;RESTORE OLD CPDLP
MOV CSPDLP,A
BIT #1,A
BEQ 2$
MOV PC,TF7
2$: BIC #1,A
JSR PC,PSTA ;POP S TO (A)
SPOP CSPDLP ;RESTORE OLD CSPDLP
JMP (E)
.GLOBL CURLIN,PROATM ;081
.GLOBL NCF,TOPS2 ;082
.GLOBL CLCNT,ERPROC ;083
RUN:
DO: JSR PC,CKSTG ;MAKE SURE THERE IS ROOM
MOV @S,A ;THE LIST TO RUN
MOV A,B ;COPY IT
BIC #7777,A ;GET TYPE
CMP #LIST,A ;IS IT A LIST
BEQ DO1 ;YES
ERROR+WTAB ;NO, THIS IS A LOSER THEN
DO1: JSR PC,BLSTI ;BUILD A LIST OF THE CHARACTERS OF THIS LIST
PUSH PCHR ;SAVE THE PRINTING ROUTINE
MOV #BLST,PCHR ;WHEN YOU PRINT A CHARACTER PUT IT INTO THIS LIST
CLR NBKTS ;NO BRACKETS NOW
JSR PC,PNODAB ;PRINT OUT THIS LIST
SPOP PCHR ;RESTORE THE PRINT ROUTINE
JSR PC,BLSTF ;NOW, FINISH THIS LIST
BEQ DO4 ;WAS THE EMPTYP LIST
MOV TOPS,@S ;PUT THE LIST WE BUILT ONTO THE STACK
JSR PC,SAVEVL ;SAVE THE EVAL STATE
PUSH #0 ;NUMBER OF ARGUMENTS
JSR PC,SAVPPS ;SAVE THE PDL POINTERS,
MOV S,A ;POINT TO THE TOP OF THE STACK
MOV (A),-(A) ;COPY THE TOKEN LIST TO CREATE A CELL FOR THE OLD COMMAND
;BUFFER
MOV ILINEL,2(A) ;STACK POINTER TO THE ILINE
MOV A,S ;FIX STACK POINTER
;HERE, WHEN A RESPPS IS DONE, THE TOP OF THE STACK IS
;THE OLD ILINEL
BIC #ERRF!CATCHF,FLAGS ;THIS CANNOT BE A BOTTOM ERROR OR CATCH FRAME
BIS #DORF,FLAGS ;THIS IS A DO FRAME!!!!!!
BIS #1,CPDLP ;I AM A PROCEDURE, PUSH ME....
MOV CPP,CURLIN+PROATM ;FAKE CPP POINTER FOR RESEVL
JSR PC,MREAD1 ;TURN CHARACTER STRING INTO THE BUFFER
BEQ 1$ ;NO TOKENS
JSR PC,EVLINE ;EVALUATE THE LINE
BNE 1$ ;DIDN'T OUTPUT
MOV #SRET,PSTOPR ;OUTPUT!!!!
BR 2$ ;RETURN....
1$: MOV #RET,PSTOPR ;JUST RETURN, NO OUTPUT
2$: MOV PSTOPR,DOFRET ;DITTOR
JMP POPFRM ;POP THE DO FRAME AND RETURN
DO4: POPS A ;POP OFF CHARACTER STRING
SEZ ;NO OUTPUT
RTS PC
.SBTTL CATCH AND THROW UP
CATCH: TST D
BNE 1$ ;BETTER BE AT LEAST ONE
2$: ERROR+WNA
1$: MOV S,A ;GET POINTER TO S PDL
DEC D ;IS THERE ONE ARGUMENT?
BEQ 3$ ;YES, JUST PUSH NULL TAG
DEC D ;BETTER JUST BE ONE MORE ARGUMENT
BNE 2$ ;NOPE, GIVE ERROR IN USER PROGRAM....
MOV 2(A),B ;GET THE LIST TO RUN
MOV (A)+,(A) ;PUT TAG BACK DOWN ON FRAME
MOV B,-(A) ;PUSH BACK THE LIST TO RUN
BR CATCH1 ;GO RUN THE LIST
3$: MOV (A),-(A) ;COPY LIST TO PUT ON TOP OF STACK
CLR 2(A) ;CLEAR THE TAG FIELD
MOV A,S ;PUT BACK POINTER
;HERE ON THE S PDL IS THE TAG AND THEN THE LIST TO RUN
CATCH1: BIS #CATCHF,FLAGS ;SET THE CATCH BIT IN FLAGS
JSR PC,DO ;ACT LIKE A RUN FRAME
BEQ 1$ ;DIDN'T OUTPUT, IGNORE IT
MOV S,A ;SHOVE DOWN ON THE S PDL
MOV (A)+,(A) ;SMASH OUTPUT ON TOP OF TAG
BIC #CATCHF,FLAGS ;CLEAR CATCH FLAG
MOV A,S ;PUT BACK POINTER
RTS PC
1$: ADD #2,S ;POP OFF THE TAG
BIC #CATCHF,FLAGS ;DONT CATCH ANYTHING ELSE
SEZ
RTS PC
;THIS IS CALLED TO THROW UP THE STACK
THROW: CLR TOPS1 ;NOT RETURNING A VALUE
TST D
BEQ THRNO ;NO ARGUMENTS, MATCH NEXT THROW
CMP #2,D ;RETURNING A VALUE?
BLO THRUP ;TWO MANY ARGS
BNE THROW1 ;NOPE, JUST SKIP THIS
SPOPS TOPS1 ;POP OFF THE OUTPUT
THROW1: SPOPS C ;GET THE TAG
BIT #7777,C ;IS IT EMPTY?
BNE THROW2 ;NO, IT IS A LEGAL TAG
CLR C ;EMPTY TAG IS SAME AS NO TAG
THROW2: MOV C,TOPS2 ;PROTECT THE TAG
MOV #THRLOP,DOFRET ;ON RETURN OF POP FRAME, COME BACK TO LOOP
MOV #THRLOP,PSTOPR
;HERE TOPS1 IS THE OUTPUT OR 0 IF NO OUTPUT
;C AND TOPS2 ARE THE POINTERS TO THE TAG ON THE THROW
THRLOP: BIT #CATCHF,FLAGS ;IS THIS A CATCH FRAME?
BNE 1$ ;YES, CHECK IT OUT
2$: TST FUNLEV ;ARE WE IN A PROCEDURE?
BNE 3$ ;YES
BIT #DORF,FLAGS ;ARE WE IN A DO OR READ FRAME?
BEQ 4$ ;NO, MUST BE AT TOP LEVEL, SO ERROR OUT
3$: JMP POPFRM ;OTHER WISE POP A FRAME
4$: ERROR+NCF ;NO CATCH FOUND
;HERE THE TOP THING ON THE PDL IS THE TAG FOR THIS CATCH OR 0
1$: MOV TOPS2,C ;GET THE TAG ON THE THROW
BEQ THRDON ;NO TAG ON THROW, MATCHES ANY CATCH
MOV @S,B ;GET THE TAG ON THE CATCH
BEQ 2$ ;A TAGGED THROW DOESN'T MATCH A UNTAGGED CATCH
JSR PC,EQUAL1 ;COMPARE THE TAGS
BEQ 2$ ;DIFFERENT TAGS, CONTINUE SEARCH
;HERE THE CURRENT FRAME IS CORRECT, JUST CHECK FOR OUTPUT
THRDON: CLR TOPS2 ;NO LONGER NEED TAG
TST TOPS1 ;OUTPUTTING?
BEQ 1$ ;NO, DONT OUTPUT
SPUSHS TOPS1 ;PUSH IS BACK ON S
CLR TOPS1 ;CLEAR THE GC PROTECT
CLZ
1$: RTS PC ;OUTPUT
THRNO: CLR C ;NO TAG FOR THIS THROW
BR THROW2
THRUP: ERROR+WNA ;BAD ARGUMENTS TO THROW
SAVEVL: POP F ;SAVE THE WORLD
SPUSH CPBND
SPUSH CLCNT
SPUSH CPLN
SPUSH CTP
SPUSH FLAGS
SPUSH CO
SPUSH CT
SPUSH IFLEV
SPUSH ERPROC
JMP (F)
RESEVL: POP F
SPOP ERPROC ;PROC, RESTORE REST OF WORLD
SPOP IFLEV
SPOP CT
SPOP CO
SPOP B
SPOP CTP
SPOP CPLN
SPOP CLCNT
SPOP CPBND
SAVE A
MOV @CPBND,A
MOV PROATM(A),CPP
REST A
JMP (F)
.SBTTL "TO" ETC.
.GLOBL EDITA,ELW,ETYO,LDE,PARRYS,TOPRNM ;084
.GLOBL $LINE,$TITLE,CTIT,NEC,PARRYF,PBEX,PNH,PRMTCH,TEMP ;085
.GLOBL PAE,REDFLG,UBL ;086
GTLN: JSR PC,GTUOEB ;GET LINE # FROM NEXT TOKEN INTO B
BEQ GTLN2 ;CANT FIND IT
MOV #SNUM,A
JSR PC,CONVER ;MAKE NEXT TOKEN INTO AN SNUM
GTLN2: RTS PC
GTLP: PUSH CPBND ;SAVE POINTER TO EXECUTING PROCEDURE
MOV PARRYS,CPBND ;GET POINTER TO EDITING PROCEDURE
JSR PC,GTLINE ;GET POINTER TO LINE IN B
BEQ GTLP2 ;LOSES
POP CPBND ;GET BACK CPBND
MOV B,F ;RETURN POINTER
MOV PARRYS,PBASE ;SET UP BASE POINTER
SUB @PBASE,F ;FIX THIS POINTER
RTS PC
GTLP2: SPOP CPBND ;ERROR OUT
ERROR+LDE ;LINE NOT HERE
EDTITL: TST TOPRNM
BNE 1$
ERROR+OIP ;ONLY IN PROCEDURE
1$: JSR PC,EDITA ;SET UP FOR EDIT BUFFER INSERT
PUSH PCHR
MOV #ETYO,PCHR
MOV TOPRNM,B
JSR PC,SHTITL ;"PRINT" TITLE LINE INTO EDIT BUFFER
BNE 2$
.BUG.
2$: MOV PC,EDTIF2
BR EDLIN1
EDLINE: TST TOPRNM
BNE 1$
ERROR+OIP
1$: JSR PC,GTLN ;GET LINE # IN B
BNE 2$
ERROR+ELW ;EDIT LINE WHAT
2$: JSR PC,GTLP ;GET PTR TO THAT LINE
JSR PC,EDITA
PUSH PCHR
MOV #ETYO,PCHR
JSR PC,PRLN ;"PRINT" THE LINE TO THE EDIT BUFFER
EDLIN1: POP PCHR
SEZ
RTS PC
.GLOBL SIZE
;HERE WE LOOK FOR THE TOKEN $LINE OR $TITLE, IF NOT THAT WE ERROR OUT,
EDITSY:
.IFNZ ENG
CMP #$TITLE,B ;IS IT EDIT TITLE?
BEQ EDTITL ;YES
CMP #$LINE,B ;IS IT EDIT LINE?
BEQ EDLINE ;YES
.ENDC
.IFNZ FR
CMP #$TITRE,B ;AS ABOVE BUT IN FRENCH
BEQ EDTITL
CMP #$LIGNE,B
BEQ EDLINE
.ENDC
ERROR+NEC ;CAN'T BE EDITED
EDIT: BIC #EDTIF,FLAGS ;SO THAT WE ARE NO LONGER EDITING TITLES
JSR PC,GTUOEB ;GET POINTER TO THE USER OBLIST ELEMENT
BNE EDITSY ;WASN'T A UOE
TST TOPRNM ;EDITING ANYTHING CURRENTLY?
BEQ EDIT2 ;NO
EDIT1: ERROR+CTIT ;CANT TO IN TO
EDIT2: MOV B,TEMP ;STORE THE POINTER TO THE ATOM
CLR TOPS ;MAKE SURE WE DONT CREATE A NEW BINDING
JSR PC,.BINDF ;SEE IF IT HAS A PROCEDURE BINDING
BNE EDIT4 ;IT DOES
ERROR+PNH ;PROCEDURE NOT HERE
EDIT4: TST PROSTK(B) ;IS THE PROCEDURE EXECUTING BACK UP THE STACK?
BEQ 1$ ;NO
ERROR+PBEX ;PROCEDURE BEING EXECUTED (HUNG)
1$: MOV (B),PARRYS ;SET UP FOR THE EDIT,
;POINTER TO BINDING NODE FOR THIS ARRAY
MOV SIZE(B),PARRYF ;POINT TO THE END OF THE ARRAY
SUB PROEND(B),PARRYF ;SUBTRACT POINTER TO THE END OF USED STORAGE AND DONE
EDIT5: MOV TEMP,TOPRNM ;STORE THE PROCEDURE NAME AWAY
MOV #'>,PRMTCH ;CHANGE PROMPTING CHARACTER TO >
CLR TOPS2
CLRTP1: CLR TOPS1
CLRTOP: CLR TOPS ;CLEAR ALL TEMPORARYS
RTS PC
TO: JSR PC,GTUOEB ;GET THE UOE POINTER
BEQ 1$ ;FINE
CMP #INFIX,A ;IS IT A SYSTEM FUNCTION
BHIS 2$ ;YES
ERROR+WTAB ;CANT EDIT LISTS AND SUCH
2$: ERROR+UBL ;USED BY LOGO
1$: BIC #170000,B ;GET ONLY THE POINTER PART
BIS #UFUN,B ;MAKE SURE IT IS A UFUN
MOV B,TOPS2 ;STORE IT AWAY
MOV B,TEMP ;FOR ERROR MESSAGE
CLR TOPS ;SO THAT WE DONT CAUSE A BINDING YET.
JSR PC,.BINDF ;GET THE PROCEDURE BINDING FOR PROC IN B
BEQ TO2 ;DOESN'T EXIST
BIT #EDTIF,FLAGS ;ARE WE EDITING THE TITLE?
BEQ 3$ ;NO, CHECK TO SEE IF READ FROM FILE
CMP TEMP,TOPRNM ;ARE WE USING THE SAME NAME?
BEQ TITLED ;YES, FINE
ERROR+PAE ;BARF, THIS PROCEDURE ALREADY EXISTS
3$: TST REDFLG ;IS IT INPUT FROM THE TTY?
BEQ 4$ ;YES, FAIL IMMEDIATELY
ADD CLCNT,CTP
ADD CLCNT,CTP ;MOVE POINTER TO END OF LINE
CLR CLCNT ;SAY END OF LINE
BIS #SPDF,FLAGS ;SAY WE ARE SKIPPING THIS PROCEDURE
BR EDIT5 ;CLEAN UP
4$: ERROR+PAE ;PROC (TEMP) ALREADY EXISTS
TO2: TST TOPRNM ;ARE WE IN EDIT MODE CURRENTLY?
BNE TITLED ;YES, WELL BETTER BE EDITING THE TITLE
JSR PC,TITLDF ;SET UP PROCEDURE ARRAY... RETURN POINTER IN B
MOV #FBIND,A ;SET UP THE FUNCTION BINDING TO POINT TO THE NEWLY
;CREATED ARRAY, C WAS SET UP BY .BINDF, AND IS USED
;BY GRBAD1
TOBND: MOV TEMP,PROATM(B) ;PUT THE POINTER TO THE PNAME OF THIS ATOM INTO
;THE FIRST DIMENSION
MOV B,PARRYS ;MAKE PARRYS, POINT TO THE ARRAY START
MOV #PARRYS,(B) ;AND THE ARRAY POINT TO PARRYS (FAKE A BINDING NODE)
JSR PC,GRBAD1 ;NEW FUNCTION BINDING FOR THIS ATOM
ASL C
ASL C ;MAKE POINTER TO THE NODE
ADD #NODESP+2,C ;MAKE POINTER TO THE BINDING NODE
MOV C,@PARRYS ;CLOBBER THE ARRAY TO POINT TO THE BINDING NODE
MOV PARRYS,(C) ;CLOBBER BINDING NODE TO POINT TO THE ARRAY
;IN LSI VERSION ARRAY MAY HAVE MOVED IN GRBAD1
MOV C,PARRYS ;SET UP POINTER TO THE START OF THE ARRAY
MOV F,S ;RESET S POPPING OFF ARGUMENTS TO TO: HERE, THE PROCEDURE
;IS ENTIRELY CONSISTENT AND GC MARKED
BR EDIT5 ;SET UP PROMPT AND CLEAN IT UP
;CALLED WITH C POINTING TO THE END OF THE BINDING LIST FOR THE NEW NAME
;OLD NAME IS IN TOPRNM
;TEMP POINTS TO THE NEW NAME
TITLED: BIT #EDTIF,FLAGS ;EDITING THE TITLE?
BEQ EDIT1 ;NO, CANT TO IN TO
SPUSH C ;SAVE POINTER TO THE BINDING NODE
JSR PC,CHKTIT ;CHECK THE TITLE, D <= THE NUMBER OF ELEMENTS ON LINE
;ARGUMENTS PUSHED ON THE S PDL
;F GETS THE REAL NUMBER OF ARGS
MOV @PARRYS,E ;THE START OF THE OLD ARRAY
ADD #HEADER,E ;POINT TO THE START OF THE PROCEDURE STRUCTURE
MOV F,2(E) ;PUT IN NEW NUMBER OF ARGUMENTS
SPUSH D ;SAVE ARGUMENTS
ASL D ;NUMBER OF BYTES NEEDED FOR THE ARUMENTS
ADD #2,D ;BECAUSE WE NEED A WORD SAYING HOW MANY ARGS,
SPUSH D ;SAVE THE LENGTH OF THE NEW LINE
SUB (E),D ;THE LENGTH DIFFERENCE IN BYTES
JSR PC,MAKSPA ;BYTE DIFFERENCE IN D, POINTER TO PLACE IN E
;WILL EITHER CONTRACT OR EXPAND ARRAY AS NEEDED
SPOP (E)+ ;POP THE LINE LENGTH
MOV F,(E)+ ;AND THE NUMBER OF ARGUMENTS
SPOP D ;GET THE NUMBER OF ARGUMENTS
BEQ 1$ ;NONE, FORGET IT
MOV D,A ;COPY IT
ASL A ;INTO BYTES
ADD S,A ;MAKE IT A RELATIVE POINTER TO THE S PDL
SPUSH A ;WHERE THE PDL POINTER WILL BE WHEN WE ARE DONE
2$: MOV -(A),(E)+ ;PUT IN THE ARGUMENTS
SOB D,2$ ;TAKE ALL THE ARGUMENTS OFF THE S PDL
SPOP S ;NOW RESTORE THE S-PDL
1$: CMP TEMP,TOPRNM ;ARE THE NAMES THE SAME?
BNE NEWTIT ;NO, WE MUST UNBIND THE OLD NAME, AND CREATE NEW BINDING
SPOP C ;JUST FLUSH THE NEW BINDING NODE POINTER
JMP EDIT5 ;AND CLEAN UP
NEWTIT: MOV #FBIND,A ;REMOVE THE FUNCTION BINDING
MOV TOPRNM,B ;UNBIND THE OLD ONE
SPUSH @PARRYS ;PUSH THE PROCEDURE ADDRESS
JSR PC,.UNBND ;DO THE DEED
SPOP B ;GET IT INTO B
SPOP C ;GET BACK POINTER TO WHERE THE NEW PROC BINDING GOES
MOV S,F ;PUT POINTER TO POP S TO IN F
BR TOBND ;BIND IT LIKE YOU WERE DOING A TO
GTUOEB: JSR PC,GNT ;GET UOE PTR FROM NEXT TOKEN IN B
BIT #CRF,FLAGS
BEQ 1$
ERROR+UEL ;UNEXPECTED END OF LINE
1$: BIC #7777,A ;SKIP UNLESS NEXT TOKEN NOT UOE. USES A
CMP #UFUN,A
BEQ GTU1
CMP #ATOM,A
BEQ GTU1
CMP #LSTR,A
BNE GTU2
MOV B,TOPS
JSR PC,.INTRN
GTU1: CLR TOPS
GTU2: RTS PC
CONTIN:
MOV #POPVAR,DOFRET ;POP OFF DO FRAMES
MOV #CNTIN1,PSTOPR ;AND CHECK FOR ERROR FRAMES
CNTIN1: TST FUNLEV ;IN A PROCEDURE?
BEQ CNTIN3 ;NOT ANY MORE
BIT #ERRF!BRKF,FLAGS ;IS THIS THE BOTTOM LEVEL ERROR PROCEDURE?
BNE CNTIN2 ;YES
JMP POPVAR ;POP A FRAME...
CNTIN2: MOV #CNTIN4,PSTOPR ;POP OFF THE ERROR FRAME
JMP POPVAR ;POP IT
CNTIN4: MOV #CNTIN5,DOFRET ;POP OFF ALL THE DO FRAMES
CNTIN5: BIT #DORF,FLAGS ;DO FRAME?
BEQ CNTIN6 ;NOPE
JMP POPVAR ;POP IT OFF
CNTIN6: JMP PMLOOP ;RESTART A MLOOP (I.E. THE NEXT LINE
;IF WE WANT TO ALLOW PROCEDES TO WIN TOTALLY, WE SHOULD
;MAKE SURE ALL ERROR+BRK GET CONTINUED CORRECTLY, AND
;HERE WE SHOULD CALL PSTOP. THAT IS ALL ERROR+BRKS MUST
;BE FOLLOWED BY A BRANCH TO A GOOD PLACE TO CONTINUE FROM
;JUST STOP THE ERROR FRAME, AND RETURN
CNTIN3: JMP TOPLEVEL ;JUST RETURN TO TOPLEVEL
RETURN: JSR PC,G1NARG ;GET THE LINE TO RETURN TO
MOV B,TMPBLK ;SAVE IT FOR A BIT
MOV #RETUR1,PSTOPR ;AND CHECK FOR ERROR FRAMES
MOV #POPVAR,DOFRET ;POP OFF DO FRAMES
RETUR1: TST FUNLEV ;IN A PROCEDURE?
BEQ CNTIN3 ;NOPE
BIT #ERRF!BRKF,FLAGS ;IS THIS THE BOTTOM LEVEL ERROR PROCEDURES
BNE RETUR2 ;YES, DO A JUMP TYPE THING
RETUR3: JMP POPVAR ;POP A FRAME
RETUR2: MOV #GOUNTL,PSTOPR ;AND POP THE ERROR PUSH, AND GET BACK TO PROCEDURE
BR RETUR3
GO: JSR PC,OIPTST ;MAKE SURE WE ARE IN A PROCEDURE
JSR PC,G1NARG ;GET THE LINE TO JUMP TO
MOV B,TMPBLK ;SAY IT
GOUNTL: MOV #GOUNTL,DOFRET ;COME HERE AGAIN IF IT IS A DO
BIT #DORF,FLAGS ;IS IT A DO FRAME?
BNE RETUR3 ;POP A DO FRAME
MOV CPDLP,A ;POP THE P STACK BACK TO THE START FOR THIS FRAME
BIC #1,A ;USED AS A FLAG
JSR PC,PPTA ;POP THE P TO (A)
MOV CSPDLP,A ;AND DO THE SAME TO S
BIC #1,A
JSR PC,PSTA ;POP THE S PDL TO (A)
MOV TMPBLK,B
JSR PC,GTLINE ;GET A POINTER TO THE LINE
BNE 1$
ERROR+LDE ;LINE B DOESN'T EXIST
1$: SUB @CPBND,B ;MAKE B RELATIVE
MOV B,CTP
MOV TMPBLK,CPLN
JMP PMLOOP ;JUST GO TO THE NEXT LINE
.GLOBL NSL,PROCAR,PRSIZE ;091
.GLOBL WIT ;092
.GLOBL LASTPR ;093
TITLDF: PUSH C
JSR PC,CHKTIT ;PUSH ARGUMENTS ON THE S-PDL, AND RETURN NUMBER IN D
MOV D,B ;NUMBER OF ARGUMENTS
ASL B ;NUMBER OF BYTES
ADD #4+HEADER+PRSIZE,B ;NUMBER OF BYTES IN ARRAY OVERHEAD, AND THE SIZE INIT
JSR PC,..ALLO ;ALLOCATE AN ARRAY OF THAT SIZE
BNE 1$ ;OKAY
ERROR+NSL ;NO STORAGE LEFT
1$: MOV A,C ;COPY IT
MOV A,PARRYS ;STORE THE START OF THE ARRAY (CLOBBERED LATER TO POINT TO THE
;BINDING NODE FOR THIS PROCDURE
MOV B,PARRYF ;NUMBER OF BYTES TO BE USED+HEADER LENGTH
CMP (C)+,(C)+ ;SKIP BACK POINTER TO ATOM, AND LENGTH
MOV #PROCAR,(C)+ ;PROCEDURE ARRAY
CLR (C)+ ;ONE DIMENSIONAL
CLR (C)+
CLR (C)+ ;THIS WILL BE THE TOTAL LENGTH OF THE PROCEDURE EVENTUALLY
ADD #10,C ;SKIP INFO FOR WINDOWS
MOV D,B ;NUMBER OF ARGS
INC B ;ONE FOR THE NUMBER
ASL B ;GET LENGTH IN BYTES
MOV B,(C)+
MOV F,(C)+ ;NUMBER OF ARGS
MOV S,F ;IN CASE WE BRANCH AROUND
TST D ;ANY ARGUMENTS?
BEQ TITDON ;NO, WE ARE FINISHED
MOV D,B ;NUMBER OF ARGUMENTS WE PUSHED ON S
ASL B ;INTO A BYTE NUMBER
ADD F,B ;GET NEW S POINTER
SPUSH B ;SAVE IT FOR LATER
ARGLOP: MOV -(B),(C)+ ;PUT IN POINTER TO THE ARUMENT
SOB D,ARGLOP ;FOR ALL OF THEM
SPOP F ;AND NOW SET F TO WHAT S SHOULD BE PUT BACK TO BY TOBND
TITDON: MOV PARRYS,B ;GET POINTER TO START OF THE ARRAY
SUB B,C ;GET NUMBER OF BYTES USED
MOV C,PROEND(B) ;PUT IN POINTER TO THE FIRST FREE LOCATION INTO 1 DIMENSION
SUB C,PARRYF ;AND SET UP NUMBER OF BYTES LEFT
SPOP C
RTS PC ;DONE
CHKTIT: CLR D ;COUNTER FOR NUMBER OF TOKENS
CLR F ;COUNTER FOR NUMBER OF ARGS
SAVE #2 ;FLAG
CMP SPUSHL,S ;ENOUGH ROOM ON THE S PDL?
BLOS CHKTI0 ;YES
JSR PC,SPSWPO ;SWAP OUT SOME OF S
CHKTI0: DEC CLCNT ;ANY MORE TOKENS ON THE LINE?
BMI CHKTI1 ;DONE
MOV CTP,A ;GET POINTER
ADD @CPBND,A ;RELOCATE
MOV (A),B ;GET TOKEN
MOV B,A ;COPY IT
ADD #2,CTP ;MOVE POINTER ONWARDS
BIC #7777,A
INC D
TST (P) ;ARE WE IN A COMMENT?
BLT 1$ ;NO ARGS WITHIN COMMENT
CMP #$LOCAL,B ;IS IT LOCAL?
BEQ 2$
STLANC
ENGINS < CMP #$USING,B ;USING?>
ENGINS < BEQ 2$ ;SAME>
ENDENG
FRINS < CMP #$AVEC,B ;AVEC?>
FRINS < BEQ 2$ ;TREAT AS WITH LOCAL>
ENDLAN
BR 3$ ;NOPE
2$: MOV #1,(P) ;CHANGE FLAG
BR CHKTI3 ;GO STORE IT AWAY
3$: CMP #UVAR,A
BEQ CHKTI3
CMP #UFUN,A ;BBN MODE OF VARIABLE DECLARE
BEQ CHKTI3
1$: CMP #$COMT,B ;IS IT ! ?
BNE CHKTER ;NOPE
NEG (P) ;FLIP COMMENT FLAG
CHKTI3: BIT #100001,(P) ;IS FLAG ODD OR NEGATIVE?
BNE 1$ ;COMMENT OR LOCAL ARG
INC F ;A REGULAR ARG
1$: CMP D,#MAXARG ;TO MANY ARGS?
BGE CHKTI0 ;YES, DONT PUSH ANY MORE
PUSHS B ;PUSH ON THE TOKEN
BR CHKTI0 ;AND GO FOR THE NEXT
CHKTER: TST (P) ;ARE WE IN A COMMENT?
BLT CHKTI3 ;YUP, ANYTHING GOES
TST A ;IS THE TYPE SFUN?
BNE 1$ ;NOPE, LOSER
CMP #$DOTS,B ;SPECIAL CASE
BEQ 1$
SAVE TEMP ;UGH
JSR PC,LSFUN ;CONVERT SFUN TO LSTR
MOV #UVAR,A ;TYPE FOR .INTRN
JSR PC,.INTRN ;FAKE UP AN ATOM
BIC #170000,B
BIS #UFUN,B ;FAKE UFUN
CLR TOPS
REST TEMP ;BLETCH
BR CHKTI3
1$: MOV B,CT
ERROR+WIT ;WRONG TYPE OF INPUT TO "TO"
CHKTI1: CMP #MAXARG,D
BGE CHKTI2
ERROR+TMAP ;TOO MANY ARGS (PROCEDURE)
CHKTI2: TST (P)+ ;FLUSH COMMENT FLAG
RTS PC
END: MOV TOPRNM,B
BNE 1$
ERROR+OIP ;ONLY IN PROCEDURE DEFINITION
1$: MOV B,LASTPR ;SAVE FOR "PO"
TST REDFLG
BEQ END4
BIT #SPDF,FLAGS
BEQ END3
END4: BIT #SPDF,FLAGS ;DOUBLE DEFINED?
BNE END5 ;YUP, GIVE MESSAGE
TST FUNLEV ;DON'T PRINT "FOO DEFINED" IF NOT AT TOP LEVEL
BEQ END5
BIT #BRKF,FLAGS
BEQ END3
END5: JSR PC,PPNAME
BIT #SPDF,FLAGS
BNE END1
STLANC
ENGINS <PRTXTC ^/ DEFINED/>
ENDENG
FRINS <PRTXTC ^/ EST DEFINI/>
ENDLAN
END3: MOV @PARRYS,B ;GET ADDRESS OF PROCEDURE JUST DEFINED
MOV SIZE(B),A ;GET TOTAL SIZE
SUB PROEND(B),A ;GET UNUSED SPACE
CMP #HEADER,A ;IS THERE ENOUGHROOM FOR A HEADER?
BHI END7 ;NOPE, LEAVE IT ALONE
SUB A,SIZE(B) ;GET RID OF EXCESS SPACE
ADD SIZE(B),B ;POINTER TO SPACE TO BE FREED
MOV A,SIZE(B) ;FAKE AN ARRAY HEADER
JSR PC,.RELES ;AND RELEASE THE SPACE
END7: CLR TOPRNM
BIC #SPDF,FLAGS
MOV #'?,PRMTCH
SEZ
RTS PC
END1:
STLANC
ENGINS <PRTXTC ^/ skipped/>
ENDENG
FRINS <PRTXTC ^/ a ete passe/>
ENDLAN
BR END7
.SBTTL UTILITY - COUNT LIST ELEMENTS
CLE: ;COUNT LIST ELEMENTS
;IN - LIST PTR IN C
;OUT - # OF ELEMENTS IN B
PUSH A
SPUSH C
CLR B
MOV C,A
CLE1: BIT #7777,A
BEQ CLE2
MOV A,C
JSR PC,.LDP1
INC B
BR CLE1
CLE2: POP C
SPOP A
RTS PC
.SBTTL UTILITY - ADD A LINE
;TAKES POINTER TO ATOM IN B, AND OUTPUTS NUMBER OF ARGUMENTS IN B
;SET Z IF PROCEDURE IS NOT FOUND
GNASN: PUSH A
SPUSH B
SPUSH C
JSR PC,.BNDFS ;GET THE BINDING INTO B
BNE 1$ ;FOUND IT
JMP RETC
1$: ADD #HEADER,B ;POINT TO THE START OF THE PROCEDURE
MOV 2(B),2(P) ;PUT THE # OF ARGS INTO B ON THE STACK
JMP SRETC
GTLINE: ;LINE NUMBER IN B, OUTPUT POINTER TO LINE IN B
;PROCEDURE POINTED TO BY CPADR
;SET Z IF NOT FOUND
SPUSH A
SPUSH B
SPUSH C
SPUSH D
MOV @CPBND,C ;GET POINTER TO THE START OF THE ARRAY
MOV PROEND(C),D ;POINTER TO THE END OF THE ARRAY
ADD C,D ;MAKE IT AN ABSOLUTE POINTER
ADD #HEADER,C ;POINT TO THE START OF THE DATA
GTLIN1: ADD (C)+,C ;GET TO THE NEXT LINE
CMP C,D ;ARE WE AT THE END OF THE PROC?
BEQ GTLINF ;YES, WE HAVE FAILED TO FIND IT
BHI GTLINB ;OOPS WE SHOULDN'T OVERSHOOT
CMP B,2(C) ;ARE THE LINE NUMBERS THE SAME?
BGT GTLIN1 ;THE ONE WE ARE LOOKING FOR IS FURTHER ON
BLT GTLINF ;WE PASSED WHERE IT SHOULD BE, FAIL
MOV C,4(P) ;CLOBBER B ON THE STACK
JMP SRETD ;AND RETURN
GTLINF: JMP RETD
GTLINB: .BUG.
;CALLED WITH THE LINE NUMBER IN B
;IF NEGATIVE DELETE THAT LINE
;IF NOT INSERT LINE POINTED TO BY CTP, CLCNT IS EXPECTED TO BE CORRECT
ADLN: JSR F,CACSAV ;CAREFULLY SAVE THE AC'S
CLR A ;A FLAG
MOV B,F ;THE LINE NUMBER
BPL FINLIN ;FIND THE LINE AND INSERT IT
NEG F ;GET THE REAL LINE NUMBER
INC A ;FLAG FOR JUST DELETING LIEN
FINLIN: MOV @PARRYS,E ;POINTER TO THE START OF THE ARRAY
MOV PROEND(E),B ;THE POINTER TO THE FIRST FREE LOCATION
ADD E,B ;MAKE IT ABSOLUTE
ADD #HEADER,E ;POINT TO THE BEGINNING OF THE PROCEDURE
LINLOP: ADD (E)+,E ;POINT TO THE NEXT LINE
CMP E,B ;ARE WE AT THE END?
BEQ ADDEND ;YES
BHI ADDBUG ;CANT BE...
CMP F,2(E) ;ARE THE LINE NUMBERS THE SAME?
BGT LINLOP ;NO, IT MUST BE FURTHER ON
BEQ LINEQ ;INSERT THE LINE (E)
ADDEND: TST A ;DELETING THE LINE?
BNE LINDN2 ;CANT FIND THE LINE TO DELETE IT
JSR PC,LINLEN ;GET THE LENGTH OF THE LINE IN BYTES INTO D+4 FOR
;LENGTH AND LINE NUMBER
JSR PC,MAKSPA ;AND MAKE SPACE FOR IT
SUB #2,D ;SUBTRACT FOR THE LENGTH WORD
MOV D,(E)+ ;SET IN THE LINE LENGTH
MOV F,(E)+ ;THE LINE NUMBER
LINDON: JSR PC,INSLIN ;AND THE LIST
LINDN2: JSR F,CACRES
RTS PC
ADDBUG: .BUG.
;HERE WE DELETE THE LINE (E), AND INSERT LINE POINTED TO BY A
LINEQ: TST A ;ANY LIST TO INSERT?
BNE NOLIST ;NO JUST DELETE THE LINE
JSR PC,LINLEN ;GET THE LENGTH OF THE LINE IN D
SUB #2,D ;BECAUSE WE DONT COUNT THE LENGTH WORD NOW
SPUSH D ;SAVE IT FOR LATER
SUB (E),D ;GET THE DIFFERENCE BETWEEN THE TWO LINES
JSR PC,MAKSPA ;MAKE SPACE FOR THE LINE
SPOP (E)+ ;SET IN THE LENGTH
MOV F,(E)+ ;AND LINE NUMBER
BR LINDON ;DONE WITH THE LINE
NOLIST: MOV (E),D ;GET THE NUMBER OF DELTA BYTES
ADD #2,D ;BECAUSE WE ARE DELETING THE LENGTH ALSO
NEG D ;IT IS GETTING SMALLER
JSR PC,MAKSPA ;FIX THIS LINE
BR LINDN2 ;JUST RETURN
;RETURN NUMBER OF BYTES NEEDED FOR THE LINE IN D
LINLEN: MOV CLCNT,D ;GET NUMBER OF TOKENS LEFT
ASL D ;FROM WORDS TO BYTES
ADD #4,D ;FOR THE LINE NUMBER, AND LENGTH
RTS PC
;PUT LINE POINTED TO BY CTP INTO ARRAY POINTED TO AT E
INSLIN: TST CLCNT ;ARE THERE ANY MORE TOKENS LEFT?
BEQ INSDON ;NO
MOV @CPBND,B ;GET POINTER TO THE START OF THE LINE'S PROCEDURE
ADD CTP,B ;POINT TO THE LINE TO INSERT
MOV CLCNT,C ;NUMBER OF TOKENS TO INSERT
ADD C,CTP ;MUST FIX CTP
ADD C,CTP ;TO POINT TO END OF LINE
1$: MOV (B)+,(E)+ ;COPY THE TOKENS
SOB C,1$
INSDON: RTS PC
.GLOBL PROINC ;098
;MAKE SPACE FOR D BYTES AT (E). IF D IS NEGATIVE COLLAPSE SPACE.
;IF D IS POSITIVE, EXPAND THE ARRAY IF NEEDED, COPY THE ARRAY, LEAVING D
;BYTES AT THE ORIGINAL E
;PARRYS AND PARRYF ARE UPDATED IF NEEDED, AND 1 DIMENSION OF ARRAY ALSO
MAKSPA: TST D
BEQ SPADON ;NOTHING NEED BE DONE
BPL SPAEXP ;NEED TO EXPAND MAYBE
JSR F,CACSAV ;SAVE THE AC'S
SUB D,PARRYF ;MAKE THE FREE SPACE A LITTLE LARGER
MOV @PARRYS,A ;POINT TO THE START OF THE ARRAY
MOV PROEND(A),B ;GET POINTER TO THE FIRST UNUSED LOCATION
ADD A,B ;MAKE IT AN ABSOLUTE POINTER
ADD D,PROEND(A) ;DECREASE THE POINTER BY THE AMOUNT SHIFTED DOWN
MOV E,F ;COPY POINTER TO WHERE WE ARE MUNGING
SUB D,F ;MAKE IT POINT AHEAD D BYTES
SUB F,B ;GET NUMBER OF BYTES TO TRANSFER
BLE SPADN1 ;NUMBER OF BYTES DELETING IS MORE THAN FROM (E) TO END OF PROC.
ASR B ;GET NUMBER OF WORDS
MAKSP1: MOV (F)+,(E)+ ;TRANSFER THEM
SOB B,MAKSP1 ;FOR ALL THE BYTES
SPADN1: JSR F,CACRES ;GET BACK THE AC'S
SPADON: RTS PC ;AND RETURN
SPAEXP: JSR F,CACSAV ;SAVE THE AC'S
CMP D,PARRYF ;IS THERE ENOUGH FREE SPACE TO WIN ON THIS PROCEDURE?
BLE NUFSPA ;YES
;HERE WE HAVE TO TRY TO EXPAND THE ARRAY
MOV @PARRYS,A ;POINT TO THE BEGINNING OF THE CURRENT ARRAY
MOV SIZE(A),B ;GET THE CURRENT SIZE
SUB A,E ;MAKE POINTER TO WHERE TO INSERT RELATIVE TO OLD ARRAY START
ADD D,B ;GET NEW NUMBER OF BYTES NEEDED
ADD #PROINC,B ;AND ADD A LITTLE EXTRA FOR EFFICIENCY
JSR PC,..ALLOC ;GET A NEW ARRAY OF THAT SIZE, POINTER IN A
BEQ NOSPA ;NO SPACE
MOV @PARRYS,C ;GET ADDRESS OF OLD ARRAY
ADD C,E ;MAKE IT POINT TO THE POSSIBLE NEW PLACE
;HERE THE OLD ARRAY IS CONSISTENT AGAIN, NEW ARRAY POINTED TO BY A, OLD BY C
;PARRYS IS NOT CONSISTANT YET
ADD #PROINC,PARRYF ;ADD SOME SPACE TO THE FREE COUNT
MOV C,B ;COPY POINTER TO OLD ARRAY
MOV A,F ;COPY POINTER TO THE NEW ARRAY
ADD #PROTYP,F ;POINT TO THE START OF THE INFO IN THE NEW ARRAY
ADD #PROTYP,B ;POINT TO THE START OF THE INFO IN THE OLD ARRAY
SUB B,E ;GET THE BYTE COUNT FROM BOTTOM TO INSERTED AREA
BEQ TOPPRT ;NO BYTES BELOW AREA, MOVE REST OF AREA UP
ASR E ;INTO A WORD COUNT
1$: MOV (B)+,(F)+ ;COPY UP THE BOTTOM OF THE ARRAY
SOB E,1$ ;ALL THE WORDS IN THE BOTTOM
TOPPRT: MOV F,10(P) ;CLOBBER THE STORED E ON THE STACK
SUB A,10(P) ;MAKE IT RELATIVE
ADD D,F ;SKIP D BYTES
MOV PROEND(C),E ;GET THE POINTER TO THE END OF THE ARRAY
ADD C,E ;MAKE IT UNRELATIVE AGAIN
SUB B,E ;SUBTRACT WHERE WE HAVE GOTTEN
BEQ SPADN2 ;DONE IF NO BYTES ABOVE THIS POINT
ASR E ;INTO A WORD COUNT
2$: MOV (B)+,(F)+ ;MOVE IT UP IN THE NEW ARRAY
SOB E,2$ ;FOR ALL THE WORDS IN THIS ARRAY
SPADN2: MOV A,@PARRYS ;UPDATE THE POINTER TO THE ARRAY
MOV (C),(A) ;SET UP BACK POINTER TO BINDING NODE
SUB A,F ;MAKE POINTER TO END RELATIVE AGAIN
MOV F,PROEND(A) ;SET IN POINTER TO THE END OF THE PROC
MOV C,B ;COPY POINTER TO THE OLD ARRAY
JSR PC,.RELES ;AND RELEASE IT
ADD @PARRYS,10(P) ;MAKE THE POINTER ON THE STACK ABSOLUTE AGAIN
BR SPADN1 ;AND FINISH UP
NOSPA: ERROR+NAS ;NOT ENOUGH ARRAY SPACE (MAYBE CHANGED TO NO STORAGE LEFT)
NUFSPA: SUB D,PARRYF ;DECREASE THE AMOUNT OF FREE SPACE
BMI MAKBUG ;BUG IF IT GOES NEGATIVE
MOV @PARRYS,A ;POINT TO THE START OF THE ARRAY
MOV PROEND(A),B ;GET THE POINTER TO THE END OF THE ARRAY
ADD A,B ;MAKE IT NON RELATIVE
ADD D,PROEND(A) ;MAKE THE POINTER A LITTLE HIGHER
MOV B,A ;COPY IT
SUB E,A ;GET THE NUMBER OF BYTES TO COPY
BEQ SPADN1 ;NOTHING TO COPY
ASR A ;GET THE NUMBER OF WORDS TO COPY
MOV B,C ;POINTER TO THE TOP OF THE ARRAY
ADD D,C ;POINT TO THE RIGHT SPOT ABOVE THE ARRAY
MAKSP2: MOV -(B),-(C) ;COPY IT UP
SOB A,MAKSP2
BR SPADN1 ;ALL DONE
MAKBUG: .BUG.
.SBTTL UTILITY - LOAD AND STORE
.LOADA: MOV A,B ;(A) -> A,,B
BR .LOAD
.LOADC: MOV C,B ;NODE ADDR IN C
;NODE RETURNED IN A,B
.LOADB:
.LOAD: BIC #170000,B ;NODE ADDR IN B
ASL B ;NODE RETURNED IN A,B
ASL B
ADD #NODESP,B
MOV (B)+,A
MOV (B),B
RTS PC
.STORE: SPUSH C ;NODE ADDR IN C
BIC #170000,C
ASL C ;NODE IN A,B IS STORED AT C
ASL C
ADD #NODESP,C
MOV A,(C)+
MOV B,(C)
SPOP C
RTS PC
.STP2: ;SAME AS .STP1 EXCEPT STORE IN 2ND WORD OF NODE
SEC ;THEN RESULT OF ROL'S WILL BE TWO GREATER THAN .STP1
BR .STP9
.STP1: CLC ;STORE (A) IN FIRST WORD OF NODE AT C
.STP9: SPUSH C ;NODE ADDR IN C
BIC #170000,C
ROL C
ROL C
ADD #NODESP,C
MOV A,(C)
SPOP C
RTS PC
.LDP2: SEC ;NODE ADDR IN C (TYPE FIELD =0)
BR .LDP9 ;LOAD 2ND WORD OF NODE INTO A
.LDP1: CLC ;SAME AS .LDP2 EXCEPT 1ST WORD
.LDP9: MOV C,A
BIC #170000,A
ROL A
ROL A
ADD #NODESP,A
MOV (A),A
RTS PC
.LDP2I: MOV C,A ;SAME AS .LDP2 EXCEPT C WILL
BIC #170000,A ;CONTAIN ADDR OF NEXT NODE
ASL A
ASL A
ADD #NODESP,A
MOV (A)+,C
MOV (A),A
RTS PC
.SBTTL UTILITY - BINDING
;INPUT: A=TYPE B=UOE POINTER
; TOPS=0 OR TYPE+VALUE POINTER
;OUTPUT: A - UCHANGED
; B - EITHER UNCHANGED OR VALUE POINTER
; C - POINTS TO BINDING NODE, EITHER
; RELEVANT ONE OR LAST IN BINDING LIST
; IF TOPS = 0, SKIPS IF BINDING FOUND
; IF TOPS NOT = 0, TOPS WILL BE INSERTED
; AS THE NEW VALUE POINTER (A NEW BINDING
; NODE WILL BE ADDED IF NECESSARY) NEVER SKIPS.
.BINDL: TST TOPS
BEQ .BIND
PUSHS TOPS
CLR TOPS
JSR PC,.BIND
BEQ .BNDL2
POPS TOPS
CLZ
RTS PC
.BNDL2L: POPS TOPS
SEZ
RTS PC
.BIND: PUSH D
SPUSH B
SPUSH A
MOV B,A
BINDF1: MOV A,C
JSR PC,.LOADC
MOV A,D
BIC #7777,D
CMP (P),D
BEQ BINDF4 ;FOUND IT
BIT #7777,A
BNE BINDF1
TST TOPS ;DIDNT FIND IT
BEQ BINDF2 ;SHOULD ONE BE CREATED?
SPOP A
MOV TOPS,B
JSR PC,GRBAD1
BINDF5: POP D ;OLD B
BINDF3: SPOP D
SEZ
RTS PC
BINDF2: POP A ;NO, DONT CREATE NODE
SPOP B
BR BINDF3
BINDF4: TST TOPS ;FOUND, CHANGE VALUE POINTER?
BEQ BINDF6
MOV TOPS,A ;YES + DONT SKIP
JSR PC,.STP2
POP A
BR BINDF5
BINDF6: POP A ;NO, LEAVE VALUE POINTER, BUT SKIP
SPOP D ;OLD B
SPOP D
CLZ
RTS PC
.UNBND: PUSH A ;ERASE TYPE (A) FROM UOE (B)
SPUSH B ;SKIP UNLESS NOT FOUND
SPUSH C
SPUSH D
MOV B,C
.UNB1: MOV C,D
MOV B,C
BIT #7777,C
BNE 1$
JMP RETD
1$: JSR PC,.LOADC
MOV A,B
BIC #7777,A
CMP 6(P),A
BNE .UNB1
MOV D,C
JSR PC,.LDP1
BIC #7777,A
BIC #170000,B
BIS B,A
JSR PC,.STP1
JMP SRETD
.BINDF:
.BNDFS: MOV #FBIND,A ;SAME AS .BINDF EXCEPT DONT SWAPIN
JSR PC,.BINDL
BIF1: RTS PC
.SBTTL .INTRN!!
.GLOBL TF5 ;103
.OBSCH: ;SAME AS .INTRN EXCEPT WONT INSERT IF ENTRY ISNT FOUND
;(ALSO SEE UOBSCH ON NEXT PAGE)
CLR TF5
BR OBSCH9
.INTRN: ;(ALSO SEE UINTRN ON NEXT PAGE)
;INPUT: TYPE IN A, LSTR IN "TOPS"
;OUTPUT: IF TYPE IS UFUN OR SFUN,
; SEARCH SYSTEM OBLIST FIRST.
; IF FOUND THERE, RETURN THAT PTR IN B,
; MAKING TYPE OF A TO "SFUN".
; IF NOT FOUND THERE, AND IF A=UFUN, OR IF TYPE
; IS > "UFUN", DO THE LOOKUP IN THE USER OBLIST.
; RETURN WITH THE UOE PTR IN B.
; DONT SKIP IF A NEW ONE HAD TO BE ADDED,
; OR IF IN SEARCHING FOR AN SFUN
; ONE WAS NOT FOUND.
;******* NOTE ********
;A NEW UOE IS "TOTALLY USELESS" AND SO MUST BE PROTECTED FROM G.C.
MOV PC,TF5
OBSCH9: PUSH A
SPUSH B
SPUSH C
MOV TOPS,C
CMP #UFUN,A ;IS TYPE SFUN OR UFUN
BLO INT2 ;NO
JSR PC,SSOL ;YES, SEARCH SYSTEM OBLIST
BEQ INT1 ;NOT THERE
MOV #SFUN,4(P) ;SET TYPE TO "SFUN"
BR INT5
INT1: CMP #SFUN,A ;IS A = TYPE SFUN
BEQ INT0 ;YES, DONE, DONT SKIP
INT2: JSR PC,HSSL ;NO, HASH TO AND SEARCH SUBLIST
BEQ INT3 ;NOT FOUND
INT5: MOV B,2(P)
JMP SRETC ;FOUND ATOM
INT3: TST TF5 ;NOT THERE, SHOULD IT BE ADDED
BEQ INT0 ;NO, RETURN AND DONT SKIP
SPUSH B ;SAVE WORD POINTER TO UHCT ENTRY TO SPLICE THIS INTO
MOV #LIST,A
MOV #ATOM,B
JSR PC,GRBAD ;CONS UP NEW LAST NODE
; (STRANGE TYPE LEST GARBAGE COLLECT)
BIS #LIST,C
PUSHS C ;SAVE POINTER TO IT, ALSO FOR G.C.
MOV #ATOM,A
MOV TOPS,B
JSR PC,GRBAD2 ;CONS UP ATOM NODE; NEW BUCKET NODE PTS TO IT
MOV C,4(P) ;SO WILL B ON RETURN
POPS C ;THE POINTER TO THE NEW BUCKET NODE WITH LIST TYPE
BIC #LIST,C ;GET BACK POINTER TO NEW BUCKET NODE
MOV @(P),A ;GET THE ENTRY THAT WAS IN THE UHCT IN THIS SLOT
BIS #BUKTEL,A ;MAKE THE NEW POINTER POINT TO THE REST OF THE ENTRIES
JSR PC,.STP1
BIS #BUKTEL,C ;MAKE THE POINTER A BUCKET POINTER
MOV C,@(P)+ ;PUT THE NEW POINTER INTO THE UHCT
INT0: JMP RETC
;"UNPURE" .INTRN AND .OBSCH
;BY "UNPURE" IT IS MEANT THAT THE INPUT STRING MAY INCLUDE
;NULL CHARACTERS
;SPECIFICATIONS ARE OTHERWISE IDENTICAL TO .INTRN AND .OBSCH
;ROUTINE TO PURIFY STRING
UINOB: PUSH A
PUSH B
PUSH C
MOV TOPS,B
JSR PC,CPYSTR ;OUTPUT POINTER IN B TO STRING WITH NO NULLS
BIS #LSTR,B
MOV B,TOPS
POP C
POP B
POP A
RTS PC
UINTRN: SPUSH #.INTRN
BR UINOB
UOBSCH: SPUSH #.OBSCH
BR UINOB
.SBTTL SEARCH SYSTEM OBLIST
.GLOBL ABRFLG,SOBP2,SOOMX ;105
.GLOBL HCC,UHCT ;106
SSOL: ;SEARCH SYSTEM OBLIST
;INPUT: C POINTS TO STRING
;OUTPUT: SKIP = FOUND AND SOE PTR IN B
; NO SKIP = NOT FOUND AND NO CHANGE
;NULL MUST BE USED AS FILLER CHAR BUT NOT BE IMBEDDED
PUSH A
SPUSH B
SPUSH C ; -> STRING (DESIRED PNAME)
SPUSH D ; -> CURRENT PNAME
SPUSH E ; 2^N
SPUSH F ; -> SYSTEM OBLIST ELEMENT
MOV SOBP2,E ;GET 2^N
MOV #SOBLST,F ;GET START OF OBLIST
SSOL1: ASR E ;HALVE 2^N
BIT #177776,E ;NOT FOUND IF 2^N = 1
BEQ SSOL5
ADD E,F ;ADD 2^N TO OBLIST PTR
CMP F,SOOMX ;OVERSHOT END OF LIST THEN UNDO ADD
BHIS SSOL2
MOV (F),D
ADD #4+SOBLST,D ;FIND START OF THIS PNAME
MOV C,A ;AND DESIRED PNAME
SSOL4: JSR PC,.LOADA ;GET TWO CHARS OF DESIRED
CMPB B,(D)+
BHI SSOL1 ;PNAME < DESIRED: ADD 2^(N-1)
BLO SSOL2 ;PNAME > DESIRED: UNADD 2^N AND ADD 2^(N-1)
SWAB B
CMPB B,(D)+
BHI SSOL1 ;PNAME < DESIRED
BLO SSOL2 ;PNAME > DESIRED
BIT #7777,A ;MORE PNAME TO COMPARE?
BNE SSOL4 ;YES
TSTB B ;MATCHING NULLS FOUND?
BEQ SSOL3 ;FOUND
TSTB (D) ;AT END OF STRING, IS IT END OF SYS PNAME
BNE SSOL2 ;NO: TRY ANOTHER (COUNT AS OVERSHOOT)
SSOL3: MOV (F),F ;POINTER TO OBLIST ELEMENT
.IFNZ ENG&FR
BIT LANG,SOBLST(F)
BEQ SSOL5
.ENDC
BIT #ABRFLG,SOBLST(F) ;IS IT AN ABBRVIATION?
BEQ 1$
MOV 2+SOBLST(F),F ;YES, "EXPAND" IT
1$: ASR F
MOV F,10(P) ;YES, SAVE F AS OUTPUT
JMP SRETF
SSOL5: JMP RETF
SSOL2: SUB E,F ;UNADD 2^N
BR SSOL1
.SBTTL HASH AND SEARCH USER SUB-OBLIST
HSSL: ;HASH, THEN SEARCH SUB-LIST
;INPUT: C POINTS TO LSTR
;OUTPUT: IF NOT FOUND, B IS A WORD POINTER
; TO THE UHCT ENTRY TO SPLICE IT INTO
; IF FOUND, B POINTS TO ATOM CELL, AND RETURN SKIPS.
PUSH A
SPUSH B ;PTR TO THIS PNAME
SPUSH C ;PTR TO DESIRED PNAME
SPUSH D ;NEXT OLE
SPUSH E ;THIS OLE
MOV C,A ;PTR TO STRING
CLR D ;SUM OF WORDS FOR HASHING
HSSLA: JSR PC,.LOADA ;GET A TWO-LETTER FRAGMENT
ADD B,D ;ADD IN
BIT #7777,A ;MORE FRAGMENTS?
BNE HSSLA ;YES
MOV D,B ;CREATE SUM OF ALL CHARS
SWAB B
ADD D,B ;IN LOWER BYTE (UPPER WON'T HURT)
CLR A
DIV #HCC,A
ASL B
ADD #UHCT,B
MOV B,-(P) ;SAVE THE POINTER TO THE UHCT ENTRY TO SPLICE IT INTO
MOV (B),A ;A POINTS TO FIRST OLE NOW
HSSL1: BIT #7777,A ;END OF BUCKET?
BNE HSSLB
MOV (P)+,6(P) ;YES: NOT-FOUND RETURN:
JMP RETE ;OUTPUT POINTER TO THE UHCT TO SPLICE IT INTO
HSSLB: MOV A,E ;SAVE PTR TO THIS OLE
JSR PC,.LOADA ;GET THIS OLE
MOV A,D ;SAVE PTR TO NEXT ONE
JSR PC,.LOADB ;GET FIRST NODE OF ATOM STRUCTURE
JSR PC,CSEQ ;CSEQ COMPARES STRINGS AT (B) AND (C)
BEQ HSSL2 ;NOT EQUAL: TRY NEXT OLE
MOV E,A ;EQUAL:
JSR PC,.LOADA ;OUTPUT ATOM POINTER
TST (P)+ ;POP OFF THE UHCT POINTER
MOV B,6(P)
JMP SRETE ;SKIP RETURN
HSSL2: MOV D,A ;NOT FOUND, CHECK NEXT BUCKET ELEMENT
BIC #LIST,E ;MAKE E A WORD PTR TO FIRST WORD OF PREV. NODE
ASL E ;IN CASE IT'S THE LAST ONE.
ASL E
ADD #NODESP,E
BR HSSL1
CSEQ: PUSH A ;COMPARE TWO STRINGS - POINTERS IN B & C
PUSH B ;SKIP IF EQUAL
PUSH C ;"NULL" (8-BIT ON) CHARACTERS
PUSH D ; DON'T MATCH CORRESPONDING 8-BIT OFF CHARS
MOV B,D ;SAVE STR 1 PTR
CSEQ1: BIT #7777,D ;CHECK IF EITHER STRING DONE
BEQ CSEQ3 ;FIRST IS: IS SECOND?
BIT #7777,C
BEQ CSEQ2 ;SECOND BUT NOT FIRST: NOT EQUAL
MOV D,A
JSR PC,.LOADA ;GET NEXT NODE OF STR 1: (A) TO A,,B
MOV A,D ;SAVE POINTER IN D
JSR PC,.LDP2I ;GET NEXT NODE OF STR 2: (C) TO C,,A
CMP A,B
BEQ CSEQ1 ;WELL, THESE WORDS MATCH
CSEQ2: JMP RETD ;STRINGS NOT EQUAL
CSEQ3: BIT #7777,C ;SEE IF BOTH STRINGS ARE DONE
BNE CSEQ2 ;NOPE, NOT EQUAL
JMP SRETD ;STRINGS EQUAL
.SBTTL UTILITY - GRAB NODE ROUTINES
.GLOBL FREE,NNIFSL ;108
GRBAD2: SEC ;GRAB A FREE NODE, FILL IT WITH A,,B
;IF C NOT =0, PUT PTR TO NEW NODE IN WORD 2 OF NODE(C)
;C ALSO GETS POINTER TO NEW NODE REGARDLESS
BR GRBAD9
GRBAD: CLR C ;SAME AS ABOVE EXCEPT NEW POINTER ALWAYS IN C
GRBAD1: CLC ;SAME AS ABOVE EXCEPT NEW PTR IN WORD 1
GRBAD9: SPUSH A
BIC #170000,C
BEQ GRB2 ;C IS ZERO, FORGET STORING NEW NODE PTR
ROL C
ROL C
ADD #NODESP,C ;ELSE MAKE NODE ADDRESS TO STORE AT
GRB2: BIT #MGCF,FLAGS2
BNE GRB4
MOV FREE,A
BNE GRB1
GRB4: JSR PC,.GCOLL
MOV FREE,A
BNE GRB1
CLR ERPROC ;DISABLE ERRSET IF 0 NODES
ERROR+NSL ;NO STORAGE LEFT
GRB1: DEC NNIFSL
BGE 1$ ;NEG NODES LEFT??
.BUG.
1$: TST C
BEQ GRB3
BIC #170000,A
BIC #7777,(C)
ADD A,(C)
GRB3: MOV A,C
JSR PC,.LDP1
; SPUSH A ;CHECK THAT NODE WAS IDLE
; BIC #7777,A
; CMP #IDLE,A
; BEQ 1$
; .BUG. ;GRABBED AN UNIDLE NODE!!!!!
;1$: SPOP A
BIC #170000,A
MOV A,FREE
SPOP A
JSR PC,.STORE
RTS PC
;.SBTTL UTILITY - FREE NODE ROUTINES
.FREE: SPUSH A ;RETURN NODE IN C TO FREE STORAGE
SPUSH B
MOV FREE,A
BIS #IDLE,A
CLR B ;MAKE SURE POINTER 2 IS ZERO
JSR PC,.STORE
BIC #170000,C
MOV C,FREE
INC NNIFSL
SPOP B
SPOP A
.FREE1: RTS PC
FRELST: BIT #7777,TOPS ;RETURN LIST (TOP-LEVEL ONLY) IN TOPS
;TO FREE STORAGE
BEQ .FREE1
PUSH A
SPUSH B
SPUSH C
MOV TOPS,C
FRL1: JSR PC,.LOADC
JSR PC,.FREE
BIT #7777,A
BEQ FRL2
MOV A,C
BR FRL1
FRL2: CLR TOPS
JMP RETC
.SBTTL READ A STRING
.GLOBL DRIBF,GCHR,RBRKF,TYI,TYO ;110
.GLOBL GETCNO,GNCN ;111
RDSTR7: MOV PC,RBRKF
SEZ
RDSTR8: RTS PC
RDSTR1: PRCR ;OUTPUT - PTR ON S, SKIP UNLESS EMPTY OR BREAK
RDSTR: CLR NBKTS
TST BRAKE
BNE RDSTR7
CMP #TYI,GCHR ;WILL CHARS BE COMING FROM TTY?
BNE RLINE1 ;NO
TST BRAKE
BEQ 1$
ERROR+BRK
1$: MOV PRMTCH,D
BEQ RLINE
BIT #BRKF,FLAGS
BEQ RLINE2
MOV FUNLEV,A
BEQ RLINE2
STLANC
ENGINS <MOV #'L,D>
ENDENG
FRINS <MOV #'N,D>
ENDLAN
JSR PC,TYO
JSR PC,PRDN
MOV PRMTCH,D
RLINE2: JSR PC,TYO
RLINE:
RLINE1: JSR PC,BLSTI
RDSTR2: JSR PC,@GCHR
CMP #TYI,GCHR
BNE RDST69
RDST2A: JSR PC,@DRIBF ;DRIBLE IT OUT IF DRIBBLING
RDST69: TST BRAKE
BNE RDSTR7
CMP #TYI,GCHR
BEQ RDSTR9
BIT #FILRED,@FILFLP
BNE RDSTR9
MOV #TYI,GCHR ;NON-TTY INPUT DONE
MOV #'],D ;FILL IN MISSING ]'S
TST NBKTS
RDSR10: BLE RDSTR4
JSR PC,BLST
DEC NBKTS
BR RDSR10
RDSTR9: CMP #TYI,GCHR ;READING FROM TTY?
BNE 1$ ;NOPE
CMP #'G-100,D ;BREAK TYPED?
BEQ RDSTR7 ;YES
CMP #'Z-100,D
BEQ RDSTR7
1$: TST NBKTS ;IN A LIST?
BGT RDSTR3 ;YES
CMP #15,D ;CR?
BEQ RDSTR4
RDSTR3: CMP #'[,D
BNE RDSTR6
INC NBKTS
RDSTR6: CMP #'],D
BNE RDSTR5
DEC NBKTS
RDSTR5: JSR PC,BLST
BR RDSTR2
RDSTR4: CLR RBRKF
JSR PC,BLSTF
BEQ RDSTR8
PUSHS TOPS
CLR TOPS
RDSTSR: CLZ
RTS PC
.SBTTL REQUEST, FILE READ & WRITE
RQUEST:
RQU1: PUSH PRMTCH
JSR PC,INPUTL
BEQ RQU5
MOV E,C ;E POINTS TO LAST NODE OF STRING
JSR PC,.LOADC ;NEED TO ADD A "]", IS THERE ROOM?
BIT #177400,B
BNE RQU2 ;YES
BIS #']*400,B ;NO - PUT A "]" THERE
JSR PC,.STORE
RQU3: MOV @S,GNCN
BIC #170000,GNCN
CLR F ;THIS IS PUSHED BY RDLST
JSR PC,RDLST
POPS TOPS
RQU4: MOV TOPS,@S
CLR TOPS
RQUR: POP PRMTCH
CLZ
RTS PC
RQU2: MOV #'],B
JSR PC,GRBAD1
BR RQU3
RQU5: MOV #LIST,@S
BR RQUR
INPUTL: MOV #'<,PRMTCH
JSR PC,GETCNO ;LAST INST OF GET CNO IS MOV (P)+,B SO FLAGS ARE SET
BEQ 1$
CLR PRMTCH
1$: JSR PC,RDSTR
BNE IPUL2
IPUL1: TST RBRKF
BEQ IPUL3
TST (P)+
SPOP PRMTCH ;NOW THE OLD PRMTCH
ERROR+BRK
IPUL3: PUSHS #LSTR
SEZ
IPUL2: RTS PC
TYPEIN: JSR PC,RQU1 ;INPUT A WORD FROM TTY
BIT #7777,@S
BNE TYPIN2
MOV #LSTR,@S
RTS PC
TYPIN2: JMP FIRST
.SBTTL READ -
.GLOBL COP,DTBL,DTBL2,OPERF,RDFLAG,SEPF,SOBLSU ;112
.GLOBL NNUMF ;113
.GLOBL LISTBD ;114
.GLOBL $DOTS ;115
.GLOBL NCHR ;116
READ: PUSH A
SPUSH B
SPUSH C
SPUSH D
SPUSH E
SPUSH F
CLR RDFLAG
MOV @S,GNCN
BIC #170000,GNCN
CLR F
READA: JSR PC,RDWRD
BEQ READB
BIS #SEPF,RDFLAG
JSR PC,CKDOTF
READC: JSR PC,LISTB
BIT #SEPF,RDFLAG
BEQ READA
READB: BIC #SEPF,RDFLAG ;CHECK SPECIAL CHAR IN D
JSR PC,CKDOTF ;FIRST CHECK FOR PENDING ":"
CMP #15,D
BEQ READR ;C-R
CMP #'",D
BEQ READS ;STRING
CMP #'[,D
BEQ READL ;LIST
CMP #'],D
BNE 1$
ERROR+COP ;CHAR (]) OUT OF PLACE
1$: CMP #':,D
BEQ READD ;DOTS
BITB #OPERF,DTBL(D) ;IS CHAR AN OPERATOR
BEQ READA ;NO
MOVB DTBL2(D),A
ASL A
MOV SOBLSU(A),B
;SET TYPE TO SFUN OR INFIX
MOV SOBLST(B),A ;THIS CROCK WORKS BECAUSE #SFUN=0
BIC #-INFIX-1,A ; AND #INFIX=10000
ASR B
BIS A,B ;SET IN THE TYPE (IF INFIX)
BR READC
READR: POPS A
CLR TOPS
TST F
BNE READR1
JMP RETF
READR1: MOV A,@S
JMP SRETF
READS: JSR PC,GNC
JSR PC,RDST
BIS #SEPF,RDFLAG
BR READC
READL: JSR PC,RDLST
POPS TOPS
BIC #SEPF,RDFLAG
BR READC
READD: BIS #DOTF,RDFLAG
BR READA
.SBTTL READ - READ WORD
;READ CHARS UP THRU NEXT SEPARATOR CHAR. IF JUST A SEP, RETURN
;WITH IT IN D. OTHERWISE NUMBERIFY OR INTERN CHAR STRING,
;SKIP RETURN WITH TOKEN IN A,,B
RDWRD: CLRB RDFLAG
JSR PC,BLSTI
RDWA: JSR PC,GNC
JSR PC,GETCHF ;GET FLAGS IN A
BIT #SEPF,A ;IS THIS CHAR A SEPARATOR?
BNE RDWB ;YES
BISB A,RDFLAG
JSR PC,BLST
BEQ RDWA
RDWB: JSR PC,BLSTF ;FINISH OFF STRING
BEQ RDWR+2
BIT #NNUMF,RDFLAG
BNE RDWC ;NOT A POSSIBLE NUMBER
MOV TOPS,B
MOV #LNUM,A
JSR PC,CONVER ;TRY MAKING A #
.IFNZ FPPF
BNE RDWR1
MOV #FNUM,A
JSR PC,CONVER ;IT MIGHT BE AN FNUM
.ENDC
BNE RDWR1
RDWC: MOV #UFUN,A ;TRY TO INTERN STRING IN TOPS AS A SYSTEM OR USER FUNCTION
BIT #DOTF,RDFLAG ; UNLESS DOTF ON, THEN AS USER VARIABLE
BEQ RDWD
MOV #UVAR,A
BIC #DOTF,RDFLAG
RDWD: JSR PC,.INTRN ;RDST COMES HERE ALSO
BEQ RDWE
JSR PC,FRELST
RDWE: BIC #170000,B
BIS A,B
CMP #UFUN,A ;IF WE GOT A UOE
BHI RDWR+2 ;THEN--
RDWR1: MOV B,TOPS ;PROTECT THIS NEWLY HATCHED UOE FROM G.C.
RDWR: CLZ
RTS PC
GETCHF: ;GET FLAGS FOR CHAR IN D INTO A
MOV #NNUMF,A
TSTB D ;CHECK FOR 200 BIT
BLT 1$
MOVB DTBL(D),A
1$: RTS PC
.SBTTL READ - READ STRING
;READ CHAR UP TO NEXT SPACE OR ] IF INSIDE
;A LIST. DONT ALLOW ] OR [.
; SKIPS UNLESS EMPTY STRING
RDST: CLRB RDFLAG
JSR PC,BLSTI
BR RDSB
RDSA: JSR PC,GNC
RDSB: JSR PC,GETCHF
BIT #SEPF,A
BEQ RDSE
JSR PC,SPACHK
BEQ RDSX
CMP #'],D
BEQ RDSC
CMP #'[,D
BEQ RDSX
CMP #15,D
BEQ RDSX
RDSE: BISB A,RDFLAG
JSR PC,BLST
BR RDSA
RDSC: TST LISTBD ;ARE WE IN LIST
BNE RDSX ;YES
RDSD: ERROR+COP ;CHAR (D) OUT OF PLACE
RDSX: MOV #LSTR,A
MOV #LSTR, B
JSR PC,BLSTF
BEQ RDWR+2
MOV #LSTR,A
MOV TOPS,B
BIT #NNUMF,RDFLAG
BEQ RDWR ;IT IS A POSSIBLE NUMBER
BIT #SEPF,RDFLAG
BNE RDWR+2 ;IT HAS A SEP CHAR IN IT
MOV #ATOM,A
BR RDWD ; INTERN IT
SPACHK: CMP #' ,D ;SPACE?
BEQ 1$ ;YUP
CMP #11,D ;TAB?
1$: RTS PC
;READ THRU MATCHING ] MAKING A LIST AS U GO
RDLST: CLRB RDFLAG
JSR PC,SLISTB
RDLA: JSR PC,GNC
JSR PC,SPACHK ;IS IT SPACE OR TAB?
BEQ RDLA ;SKIP OVER SPACES
CMP #'[,D
BEQ RDLB ;READ A LIST
CMP #'],D
BEQ RDLY ;DONE
JSR PC,RDST ;READ A STRING
RDLX: JSR PC,LISTB ;ADD THIS NODE TO LIST
CMP #'[,D
BEQ RDLB
CMP #'],D ;AT END?
BNE RDLA ;NO, GET NEXT ELEMENT
RDLY: JSR PC,FLISTB
RTS PC
RDLB: JSR PC,RDLST
POPS TOPS
CLR D
BR RDLX
.SBTTL READ - MISC
CKDOTF: BIT #DOTF,RDFLAG
BEQ LISTBR
BIC #DOTF,RDFLAG
PUSH A
SPUSH B
MOV #SFUN,A
MOV #$DOTS,B
JSR PC,LISTB
JMP RETB
LISTB: PUSH C
MOV F,C ;BUILD A LIST, ADD NODE IN A,,B TO
JSR PC,GRBAD1 ;LIST WHOSE LAST NODE PTR IS IN F
TST F ;CAREFUL - THE FIRST TIME IT IS CALLED, THE
;POINTER TO THE FIRST NODE IS PUSHED ONTO S
BNE LISTB1
PUSHS C
BIS #LIST,@S
LISTB1: MOV C,F
POP C
LISTBR: RTS PC
SLISTB: ;START LISTB
PUSHS F ;SAVE CURRENT LAST NODE PTR
CLR F
INC LISTBD
RTS PC
FLISTB: TST F
BNE FLSB1
PUSHS #LIST
FLSB1: POPS B ;THIS IS THE OUTPUT
MOV @S,F ;RESTORE OLD LAST NODE PTR
MOV B,@S ;THE RESULT
MOV #LIST,A
DEC LISTBD
RTS PC
BLSTI: CLR NCHR
MOV #100000,E
JMP CLRTOP
BLST: ;BUILD STRING - CHAR IN D, USES E
PUSH A
SPUSH B
SPUSH C
BIT #377,D ;CHECK IF NULL
BEQ BLSTRT
INC NCHR ;WE HAVE A CHAR
ADD #40000,E
BGE BLST2 ;IS IT THE SECOND
MOVB D,TEMP ;NO, 1ST
BLSTRT: JMP RETC
BLST2: MOVB D,TEMP+1 ;IT IS THE SECOND CHAR
MOV TEMP,B
;STORE THE CHARACTERS
JSR PC,BSAN
BIS #100000,E
BR BLSTRT
BLSTF: ;FINISH BUILDING STRING, PUT PTR IN TOPS.
; DONT SKIP IF EMPTY STRING (TOPS=0)
TST NCHR
BEQ BSANR ;EMPTY STRING
ADD #40000,E
BLT BSANR
PUSH A
SPUSH B
SPUSH C
MOVB TEMP,B ;YES
BIC #177400,B
JSR PC,BSAN
JMP SRETC
BSAN: MOV E,C
MOV #SSTR,A
JSR PC,GRBAD1
TST E
BNE BSAN1
MOV C,TOPS ;SAVE NEW STRING PTR ON S
BIS #LSTR,TOPS
BSAN1: MOV C,E
BSANR: RTS PC
.SBTTL GNC - GET NEXT CHAR
GNC: PUSH A ;GET NEXT CHAR INTO D
SPUSH B ;INITIALIZE BY MOVING LSTR PTR INTO GNCN
GNC4: MOVB GNCN+2,D ; AND CLEARING TYPE FIELD (#170000)
MOV GNCN,B ;PUTS CR (=#15) IN D IF NO MORE CHAR
BLT GNC1 ;JUST GOT 2ND CHAR
BNE GNC3
MOV #15,D
JMP RETB ;NONE LEFT
GNC3: JSR PC,.LOAD ;GET NEXT NODE
BIS #100000,A ;SET "STILL ANOTHER CHAR" BIT
MOV A,GNCN
MOVB B,D ;FOR OUTPUT
SWAB B
MOVB B,GNCN+2
GNC2: TST D
BEQ GNC4 ;IGNORE NULL CHARS
JMP RETB
GNC1: BIC #170000,GNCN ;CLEAR "STILL ..." BIT
BR GNC2
.SBTTL PRINT ROUTINES
PRLO: PUSH A ;PRINT LAST OPERATOR
SPUSH B
MOV LO,A
BEQ EMPTY
MOV A,B
BR PRCO1
PRCO: PUSH A, ;PRINT CURRENT OPERATOR
SPUSH B
MOV CO,A
MOV A,B
BEQ EMPTY
PRCO1: SPUSH D
JSR PC,PROAB
SPOP D
JMP RETB
PROAB: CMP A,#UFUN ;PRINT OPERATOR IN A,B
BLO PRCO2
JMP PPNAME ;PRINT PNAME
PRCO2: MOV B,A ;SYSTEM FUNCTION
BNE PRCO3
PRTXT ^\ CR.\
RTS PC
PRCO3:
BIC #170000,A ;CLEAR OUT THE INFIX TYPE
ASL A
ADD #4+SOBLST,A
BR PRAS ;PRINT ASCIZ PNAME
NOTPRO: ERROR+OOP ;SOMETHING OUT OF PLACE
EMPTY: PRTXT ^\ EMPTY \
JMP RETB
.GLOBL GETAML
ERTAS: SPUSH D
1$: SAVE A
JSR PC,GETAML
MOVB A,D
BEQ 2$
JSR PC,@PCHR
SWAB A
MOVB A,D
BEQ 2$
JSR PC,@PCHR
REST A
ADD #2,A
BR 1$
2$: REST <A,D>
ADD #2,A
RTS A
PRAS: SPUSH D ;PRINT ASCIZ STRING POINTED TO BY A
BR PRAS9
PRAS1: JSR PC,@PCHR
PRAS9: MOVB (A)+,D
BNE PRAS1
SPOP D
RTS PC
;GENERAL PRINT NUMBER ROUTINE
;CALL WITH A CLEAR, NUMBER TO BE PRINTED IN B
;MINIMUM NUMBER OF DIGITS TO PRINT IN C
;AND RADIX TO PRINT IN (=< 10.) IN D
PRN: DIV D,A
SAVE <B,#PRNDIG>
MOV A,B
CLR A
DEC C
BGT PRN
TST B
BNE PRN
RTS PC ;RETURN TO PRNDIG
PRNDIG: REST D ;DIGIT TO PRINT
ADD #60,D
JMP @PCHR
;PRINT A DECIMIAL NUMBER IN B WITH AT LEAST 2 DIGITS
ZPRDN: SAVE C
MOV #2,C ;AT LEAST 2 DIGITS
BR PRDN2
PRDN: SAVE C
CLR C
PRDN2: SAVE <A,B,D>
MOV A,B ;NEGATIVE?
BGE 1$
NEG B
MOV #'-,D
JSR PC,@PCHR
1$: MOV #10.,D
CLR A
PRDN1: JSR PC,PRN
REST <D,B,A,C>
RTS PC
PRON: SAVE C
CLR C
BR PRONL1
PRONL: SAVE C
MOV #6,C
PRONL1: SAVE <A,B,D>
MOV A,B
CLR A
MOV #8.,D
BR PRDN1
EMPTY1: JMP EMPTY
.GLOBL INVN ;121
.GLOBL WRTFLG ;122
PRS1: PUSH A ;PRINT TOP ELEMENT OF SS
SPUSH B
MOV IS,A ;COMPUTE RELATIVE S PD PTR
SUB S,A
ADD SPRBAO,A
CMP A,CSPDLP
BLOS EMPTY1
MOV @S,B
SPUSH D
JSR PC,PNODAB
SPOP D
JMP RETB
PNODAB: MOV B,A
BIC #7777,A
CMP #SSTR,A
BEQ PRS11
CMP #SNP,A
BLOS PRS11
ERROR+INVN ;INVALID NODE
PRS11: JSR PC,PRDATA
RTS PC
PRCT: PUSH A ;PRINT CURRENT TOKEN
SPUSH B
SPUSH D
MOV CT,A
MOV A,B
JSR PC,PRTAB
SPOP D
JMP RETB
PRTAB: BIC #7777,A ;PRINT TOKEN IN A,B
CMP A,#UVAR
BHIS 1$
JMP PROAB
1$: CMP A,#UVAR
BEQ PRUV
BR PRDATA
PRUV: MOVB #':,D ;PRINT USER VARIABLE IN A,B
JSR PC,@PCHR
PPNAME: BIC #PQF,FLAGS2 ;PRINT PNAME - UOE PTR IN B
PRUV1: JSR PC,.LOAD
JMP PRLSTR ;PRINT PNAME
PRDATA: CMP #INUM,A ;PRINT DATA IN A,B. 7777 FIELD OF A IS 0000
BEQ PRINUM ;NUMBER
.IFNZ FPPF
CMP #FNUM,A
BEQ PRFNUM
.ENDC
CMP #SNUM,A
BEQ PRSNUM
BIS #PQF,FLAGS2 ;SET PRINT QUOTE FLAG
PRPNM1: CMP #ATOM,A
BEQ PRUV1
CMP #LSTR,A
BEQ PRLSTR ;LONG STRING
CMP #SSTR,A
BEQ PRSSTR ;SHORT STRING
BIC #PQF,FLAGS2
CMP #LIST,A
BEQ PRLST
TST WRTFLG
BEQ PRSNP ;YES
PRTXT ^/" / ;OUTPUT EMPTY
BR PRSRET
PRSNP: PRTXT ^\%SNAP%\ ;CANT PRINT A SNAP
BR PRSRET
PRLSTR: JSR PC,.LOAD ;PRINT LONG STRING
PRSSTR: JSR PC,PRQQ ;PRINT SHORT STRING
PRSTR2: MOVB B,D
JSR PC,PRSPT
SWAB B
MOVB B,D
JSR PC,PRSPT
MOV A,B
BIC #170000,B
BEQ PRSRET
JSR PC,.LOAD
BR PRSTR2
PRSRET: RTS PC
PRQQ: BIT #PQF,FLAGS2 ;PRINT ' " ' IF PQF=1
BEQ PRSRET
BIT #DPQF,FLAGS2
BNE PRSRET
MOVB #'",D
JMP @PCHR
.IFNZ FPPF
PRFNUM: PUSH C
JSR PC,.FLOAD
MOV #FNUM,C
BR PRFNM1
.ENDC
PRSNUM: CLR A ;PRINT SNUM
TST B
BGE PRINM1
COM A
BR PRINM1
PRINUM: JSR PC,.LOAD ;PRINT INUM
PRINM1: PUSH C
.IFNZ FPPF
MOV #INUM,C ;SET FLAG FOR INUM ENTRY
.ENDC
PRFNM1: MOV E,TMPBLK+2
MOV F,TMPBLK+4
.IFNZ FPPF
CMP #FNUM,C
BNE 1$
JSR PC,.CFNST
BR 2$
1$:
.ENDC
JSR PC,.CINST ;CONVERT INUM IN A,,B TO STRING ON P
2$: MOV TMPBLK+2,E
MOV TMPBLK+4,F
MOV P,A
MOVB (A)+,D
BNE PRINM3
PRINM2: MOVB (A)+,D
BEQ PRINM4
PRINM3: JSR PC,@PCHR
BR PRINM2
PRINM4: INC A ;TO MAKE IT EVEN (??)
MOV A,P
POP C
PRSPT2: RTS PC
PRSPT: TSTB D
BEQ PRSPT2
BIT #CPTBF,FLAGS2
BEQ PRSPT1
CMPB #'%,D
BNE PRSPT1
MOV #' ,D
PRSPT1: JMP @PCHR
PRLST: PUSH A ;PRINT LIST, PTR IN B
SPUSH B
SPUSH C
TST NBKTS
BEQ PRL4
MOV #'[,D
JSR PC,@PCHR
PRL4: INC NBKTS
MOV B,C
PRL1: SPUSH FLAGS2
BIT #7777,C ;EMPTY LIST
BEQ PRL2 ;YES, DONE
BIS #DPQF,FLAGS2 ;DONT PRINT QUOTE BEFORE STRINGS
BR PRL3
PRL6: SPACE
PRL3: JSR PC,.LOADC ;GET THIS NODE
MOV A,C ;SAVE PTR TO NEXT
BIC #7777,A
JSR PC,PRTAB
BIT #7777,C
BNE PRL6
PRL2: DEC NBKTS
BEQ PRL5
MOV #'],D
JSR PC,@PCHR
PRL5: BIC #DPQF,FLAGS2
SPOP C ;GET OLD FLAGS2
BIC #<-DPQF-1>,C ;MASK ALL BUT DPQF
BIS C,FLAGS2 ;AND RESTORE IT
JMP RETC
.SBTTL PRINTOUT (ONCE KNOWN AS SHOW)
.GLOBL PODISP,SHW ;125
.GLOBL $DISPL,$PLOTT,$STTUR,ASSTPL,ASSTUR,ASTRDI,CTRDIS,CTRPLT,CTRTUR ;126
.GLOBL .POF ;127
SHALPR: ;SHOW ALL PROCEDURES
;USES A-F
JSR PC,GNOLEI
BR SHALP2
SHALP1: JSR PC,.CRLF
SHALP2: JSR PC,GNOLE
BEQ SHOWA1
JSR PC,BURYQX
BEQ SHALP2
JSR PC,PSHOW
BNE 1$
.BUG.
1$: CMP PCHR,#TYO
BNE SHALP2
BR SHALP1
POTS:
SHALTI: ;SHOW ALL TITLES
JSR PC,GNOLEI
SHATI1: JSR PC,GNOLE
BEQ SHOWA1
JSR PC,BURYQX
BEQ SHATI1
JSR PC,SHTITL
BR SHATI1
SHOWAL: JSR PC,SHALPR ;SHOW ALL PROCEDURES
JSR PC,SHALNA ;SHOW ALL NAMES
TST WRTFLG ;DON'T SHOW ARRAYS ON WRITE
BNE SHOWA1
JSR PC,POARR ;SHOW ALL ARRAYS
SHOWA1: SEZ
RTS PC
SHOW:
TST CLCNT ;ANY TOKENS LEFT
BNE SHOW00 ;YEP
MOV TOPRNM,B
BNE SHOW0
MOV LASTPR,B
BNE SHOW0
ERROR+SHW
SHOW00: JSR PC,GTUOEB
BNE SHOW1 ;THE TOKEN ISNT A USER PROC
SHOW0: JSR PC,PSHOW
BNE SHOWA1
ERROR+PNH ;PROCEDURE NOT HERE
SHOW1: CMP #SFUN,A
BNE SHOWE1
TST B ;IS IT CR?
BNE SHOW12 ;NO
MOV TOPRNM,B
BNE SHOW0
SHOWE1: ERROR+SHW
SHOW12: MOV #PODISP,A
SHOW13: CMP (A)+,B
BNE SHOW23
JMP @(A)
SHOW23: TST (A)+
TST (A)
BNE SHOW13
ERROR+SHW
.IFNZ DDF
CNTRL: CLR C
INC C
BR ALSO2
ALSO: CLR C
ALSO2: BIT #7777,CT
BNE ALSOW1
ALSOWH: ERROR+WTAB
ALSOW1: JSR PC,GNT
BIC #7777,A
CMP #SFUN,A
BNE ALSOWH
TST B
BEQ ALSOWH
.IFNZ ENG
CMP #$STTUR,B
BEQ TUR
.IFNZ NDISP
CMP #$DISPLAY,B
BEQ DIS
.ENDC
.IFNZ NPLOT
CMP #$PLOTTER,B
BEQ PLOT
.ENDC
.ENDC
.IFNZ FR
CMP #$TORTUE,B
BEQ TUR
.IFNZ NDISP
CMP #$ECRAN,B
BEQ DIS
.ENDC
.IFNZ NPLOT
CMP #$TRACEUR,B
BEQ PLOT
.ENDC
.ENDC
BR ALSOWH
.IFNZ NDISP
DIS: TST C
BEQ 1$
JMP CTRDIS
1$: JSR PC,EVAL
BEQ TUR2
JMP ASTRDI
.ENDC
TUR: TST C
BEQ TUR1
JSR PC,EVAL
BEQ TUR2
JMP CTRTUR
TUR1: JSR PC,EVAL
BNE TUR69
TUR2: ERROR+WTAB
TUR69: JMP ASSTUR
.IFNZ NPLOT
PLOT: TST C
BEQ 1$
JMP CTRPLT
1$: JMP ASSTPL
.ENDC
.ENDC
POT: MOV TOPRNM,B ;SHOW THIS TITLE
BEQ POL1
JSR PC,SHTITL
BNE POL2
.BUG.
POL: TST TOPRNM
BNE POL69
POL1: ERROR+OIP
POL69: JSR PC,GTLN ;GEN LINE NO. FROM NEXT TOKEN INTO B
BNE 1$
ERROR+SHW ;SHOW WHAT??
1$: JSR PC,GTLP ;GET POINTER TO LINE IN F
JSR PC,PRLN ;PRINT LINE
PRCR
POL2: SEZ
POL3: RTS PC
;PRINT PROC POINTED TO BY B
PSHOW: SAVE B
JSR PC,SHTITL ;CLZ IF IF PROC EXISTS; RETURNS WITH B POINTING TO ARRAY
;F POINTS TO THE FIRST LINE
BEQ PSHOW1 ;JUST RETURN
MOV @PBASE,B ;GET POINTER TO THE ARRAY
PUSH PROEND(B) ;PUSH RELATIVE POINTER TO THE END OF PROC
PSHLIN: CMP F,(P) ;AT THE END
BEQ PSHDON ;DONE
BHI PSHBUG ;ERROR
JSR PC,PRLN ;PRINT LINE OFFSET TO BY F, AND RETURN OFFSET TO NEXT LINE IN F
PRCR ;CARRIAGE RETURN
BR PSHLIN
PSHDON: TST (P)+ ;POP OFF POINTER TO THE END OF THE FILE
TST WRTFLG ;WRITING A FILE, OR PAPER TAPE
BNE 1$ ;YES, SO ALWAYS PRINT THE END
SUB TOPRNM,(P)
BIT #7777,(P)
BEQ PSHOW2 ;YES, DONT PRINT END
1$:
STLANC
ENGINS <PRTXTC ^\END\>
ENDENG
FRINS <PRTXTC ^\FIN\>
ENDLAN
PSHOW2: TST (P)+
CLZ
RTS PC
PSHOW1: TST (P)+
SEZ
RTS PC
PSHBUG: .BUG.
PON:
SHALNA: ;SHOW ALL NAMES
;USES A-F
JSR PC,GNOLEI
SHALN1: JSR PC,GNOLE ;GET NEXT UOE
BEQ POL2+2
MOV B,F
MOV #VBIND,A
JSR PC,.BINDL
BEQ SHALN1 ;NO THING FOR THIS UOE
MOV B,C ;SAVE VALUE PTR
MOV F,B ;GET UOE PTR
TST WRTFLG
BEQ SHALN2 ;NO
TST C ;IS VALUE = "UNBOUND"? (0?)
BEQ SHALN1 ;SKIP THIS ATOM
SPUSH B
STLANC
ENGINS <PRTXT ^/MAKE "/>
ENDENG
FRINS <PRTXT ^/RELIE "/>
ENDLAN
SPOP B
JSR PC,PPNAME ;PRINT THE NAME
PRTXT ^\ (\
BR SHALN3
SHALN2: JSR PC,PRUV ;PRINT THE NAME
STLANC
ENGINS <PRTXT ^/ IS/>
ENDENG
FRINS <PRTXT ^/ EST/>
ENDLAN
SHALN3: SPACE
SPUSHS C
INC NBKTS
JSR PC,PRS1
ADD #2,S
TST WRTFLG
BEQ SHALN4
PRTXT ^\ )\
SHALN4: PRCR
BR SHALN1
POARR: JSR PC,GNOLEI
POARR1: JSR PC,GNOLE ;GET NEXT UOE
.IFZ <ENG&FR>
BEQ POARR6
.IFF
BNE 1$
JMP POARR6
1$:
.ENDC
MOV B,F ;PTR TO UOE
MOV #ABIND,A
JSR PC,.BINDL ;GET ARRAY BINDING
BEQ POARR1 ;NO BINDING FOUND
JSR PC,POARR5 ;PRINT ARRAY NAME,SIZE,TYPE
BR POARR1 ;LOOK FOR MORE ARRAYS
POARR5: MOV B,C ;SAVE VALUE PTR
MOV F,B ;GET UOE PTR
JSR PC,PPNAME ;PRINT THE NAME
STLANC
ENGINS <PRTXT ^/ SIZE / >
ENDENG
FRINS <PRTXT ^/ DIMMENSION />
ENDLAN
MOV C,B ;SAVE VALUE PTR
PUSH B
JSR PC,ASIZE2 ;PUTS DIMS. OF ARAY IN LIST
MOV C,B ;PPTR TO LIST
JSR PC,PRLST ;PRINT IT
SPACE
PRTXT ^/ TYPE/
POP B ;VALUE PTR
MOV 4(B),B ;TYPE/DIM WORD IN ARRAY HEADER
BIC #7777,B ;GET THE TYPE
BEQ POARR2 ;TYPE POINTER
CMP #FNUM,B
BEQ POARR3 ;TYPE FNUM
STLANC
ENGINS <PRTXT ^/ INTEGER/>
ENDENG
FRINS <PRTXT ^/ NOMBRE ENTIER/>
ENDLAN
BR POARR4
POARR2:
STLANC
ENGINS <PRTXT ^/ POINTER/>
ENDENG
FRINS <PRTXT ^/ POINTEUR/>
ENDLAN
BR POARR4
POARR3:
STLANC
ENGINS <PRTXT ^/ FLOATING POINT/>
ENDENG
FRINS <PRTXT ^/ NOMBRE DECIMAL/>
ENDLAN
POARR4: PRCR ;CARRIAGE RETURN
SEZ
POARR6: RTS PC
PO1AR: JSR PC,GTUOEB
BEQ 1$
MOV B,F
1$: MOV #ABIND,A
JSR PC,.BINDL
.IFZ <ENG&FR>
BNE POARR5
ERROR+UDA
.IFF
BEQ 2$
ERROR+UDA
2$: JMP POARR5
.ENDC
CONTEN: ;MAKE A LIST OF ALL ATOMS THAT HAVE A PROCEDURE
CLR F
JSR PC,SLISTB
JSR PC,GNOLEI
CONTN1: JSR PC,GNOLE
BEQ CONTN2 ;DONE
JSR PC,BURYQX ;CHECK TO SEE IF IT IS BURRIED
BEQ CONTN1
MOV B,D
JSR PC,.BINDF ;A PROCEDURE
BEQ CONTN1 ;NOPE
MOV D,C
JSR PC,.LOADC ;GET PNAME
MOV #LSTR,A
JSR PC,LISTB
BR CONTN1
CONTN2: JSR PC,FLISTB
CLZ
RTS PC
;INPUT - UOE POINTER IN B
;OUTPUT - PRINTS TITLE LINE, OUTPUTS POINTER TO THE FIRST LINE OF PROC IN F, POINTER
; TO THE PROCEDURE IN B. SEZ IF NO PROCEDURE.
SHTITL: PUSH A
SPUSH B
SPUSH C
JSR PC,.BINDF ;GET POINTER TO THE FUNCTION IN B
BNE 1$ ;GOT THE BINDING
JMP RETC ;JUST RETURN
1$:
MOV (B),PBASE ;MOVE POINTER TO THE BINDING NODE INTO PBASE
STLANC
ENGINS <PRTXT ^\TO \>
ENDENG
FRINS <PRTXT ^\POUR \>
ENDLAN
MOV 2(P),B ;POINT TO THE ATOM AGAIN
JSR PC,PPNAME ;PRINT THE NAME OF THE ATOM
MOV #HEADER,F ;THE INITIAL OFFSET
ADD @PBASE,F ;MAKE IT ABSOLUTE FOR NOW
SPUSH (F)+ ;PUSH NUMBER OF BYTES IN THIS LINE
SUB @PBASE,F ;MAKE F RELATIVE
ADD F,(P) ;MAKE IT POINT TO THE NEXT LINE
ADD #2,F ;SKIP THE NUMBER OF VARIABLES
VARLOP: CMP F,(P) ;DONE?
BEQ VARDON ;YES
SPACE
ADD @PBASE,F ;MAKE POINTER ABSOLUTE
MOV (F)+,B ;GET THE POINTER TO THE VARIABLE
SUB @PBASE,F ;MAKE THE POINTER RELATIVE AGAIN
MOV B,A ;COPY IT
BIC #7777,A ;CLEAR THE POINTER PART
JSR PC,PRTAB ;PRINT THE TOKEN IN A,,B
BR VARLOP ;NEXT!!
VARDON: PRCR ;PRINT CR
SPOP F ;POP POINTER TO THE NEXT LINE
JMP SRETC ;RETURN
;INPUT - F IS OFFSET TO THE LINE TO PRINT, OUTPUT F OFFSETED TO THE NEXT LINE
PRLN: PUSH A
SPUSH B
SPUSH C
SPUSH D
ADD @PBASE,F ;MAKE F ABSOLUTE
SPUSH (F)+ ;PUSH NUMBER OF BYTES IN THIS LINE
ADD F,(P) ;MAKE IT A POINTER TO THE NEXT LINE
SUB @PBASE,(P) ;MAKE THE POINTER RELATIVE
INC NBKTS ;PRINT THE OUTER LIST BRACKETS
BIC #DPQF,FLAGS2 ;ALLOW PRINTING OF QUOTES
MOV (F)+,B ;THE LINE NUMBER
SUB @PBASE,F ;MAKE F RELATIVE AGAIN
MOV #SNUM,A ;PUT THE TYPE INTO A
JSR PC,PRTAB ;PRINT THE TOKEN IN A,,B
PRLN1: CMP F,(P) ;DONE?
BEQ PRLN2 ;YES
SPACE ;TYPE A SPACE
ADD @PBASE,F ;MAKE F ABSOLUTE
MOV (F)+,B ;GET THE NEXT TOKEN
SUB @PBASE,F ;MAKE IT RELATIVE AGAIN
MOV B,A ;COPY IT FOR THE TYPE
BIC #7777,A ;DELETE THE POINTER PART
JSR PC,PRTAB ;PRINT THE TOKEN IN B
BR PRLN1 ;NEXT TOKEN
PRLN2: DEC NBKTS ;FIX IT FOR THE NEXT CALL
SPOP F ;WELL RESTORE F
JMP RETD ;AND RETURN
.GLOBL BUG ;133
;LISTIFY THE PROCEDURE SPECIFIED
TEXTT: JSR PC,GUOEB ;GET POINTER TO THE ATOM
BNE 1$ ;OKAY
2$: ERROR+HNM ;WHAT DID YOU ASK TO TEXTIFY?
1$: JSR PC,.BINDF ;GET THE PROCEDURE BINDING
BEQ 2$ ;OUGHT TO HAVE A PROCEDURE BINDING
PUSH PROEND(B) ;PUSH THE FINISHING ADDRESS
MOV (B),PBASE ;SET UP POINTER TO THE PROCEDURE
MOV #HEADER,C ;THE INITIAL OFFSET
CLR F ;THIS IS USED BY LISTB
JSR PC,LSTIT ;LIST THE TITLE, OUTPUT IN TOPS, AND RETURNS A,,B
BR TEXTL1 ;PUT IN ON THE LIST
TEXTLP: JSR PC,LSTLIN ;LISTIFY'S LINE, AND PUSHES RETURNS IT IN A,,B
;GC-PROTECTED BY TOPS
MOV #LIST,A ;SAY THIS IS A LIST
TEXTL1: JSR PC,LISTB ;AND BUILD ME A LIST
CLR TOPS ;CLEAR THE GC-PROTECTION
CMP C,(P) ;ARE WE AT THE END OF THE PROC YET?
BLO TEXTLP ;NOT YET, GET NEXT LINE
BHI TEXTBG ;PAST IT, BUGGGGGG
TST (P)+ ;POP OFF END OF PROC MARKER
CLZ ;DONE
RTS PC
TEXTBG: ERROR+BUG
;TAKES OFFSET TO LINE IN C, LISTIFY'S IT, AND RETURNS IT IN A,,B, AND IN TOPS
LSTLIN:
MOV C,D ;COPY OFFSET TO TITLE LINE
ADD @PBASE,D ;MAKE IT ABSOLUTE
PUSH 2(D) ;SAVE THE LINE NUMBER
JSR PC,LTOK ;LISTIFY THE LINE
SPOP B ;GET THE LINE NUMBER
SPUSH C ;SAVE POINTER TO NEXT LINE
JSR PC,.CSNLS ;CONVERT IT TO AN LSTR
MOV B,TOPS ;GC-PROTECT THE NUMBER
MOV @S,A ;POINTER TO THE LINE
BIC #170000,A ;CLEAR THE TYPE
BIS #LSTR,A ;SAY THIS IS AN LSTR
JSR PC,GRBAD ;GET A NODE THAT POINTS TO THE NUMBER, AND THE LINE
BIS #LIST,C ;THIS IS THE POINTER TO THE LINE
MOV C,B ;COPY IT
MOV B,TOPS ;SAVE IT TO GC-PROTECT IT
MOV #LIST,A ;MAKE IT LIST TYPE
SPOP C ;AND GET BACK POINTER TO THE NEXT LINE
ADD #2,S ;POP OFF THIS LIST (IT ISN'T NEEDED)
RTS PC
.GLOBL $TOTO ;134
;TAKES POINTER TO THE PROCEDURE ARRAY IN PBASE AND B, AND OFFSET TO THE TITLE LINE IN C
;RETURNS C OFFSETED TO THE FIRST REAL LINE OF PROCEDURE
LSTIT:
ADD B,C ;MAKE C ABSOLUTE
MOV PROATM(B),B ;GET POINTER TO THE PROCEDURE ATOM
JSR PC,.LOAD ;AND GET POINTER TO THE PNAME
SPUSH B ;AND PUSH IT
SUB @PBASE,C ;MAKE C RELATIVE AGAIN
JSR PC,LTOK ;GET THE VARIABLES LISTIFIED, AND OUTPUT ON S PDL
SPUSH C ;SAVE POINTER TO THE NEXT LINE
MOV #LSTR,A ;MAKE THE LSTR POINT TO "TO"
STLANC
ENGINS <MOV #$TOTO,B>
ENDENG
FRINS <MOV #$POURX,B> ;GET POINTER TO "TO"
ENDLAN
JSR PC,GRBAD ;C POINTS TO NODE WITH "TO" IN IT
MOV C,TOPS ;THIS WILL BE POINTER TO THE LINE
MOV @S,A ;GET POINTER TO THE LIST OF VARIABLES
BIC #170000,A ;CLEAR OUT THE TYPE
BIS #LSTR,A ;THE PNAME IS AN LSTR
MOV 2(P),B ;THE POINTER TO THE PNAME OF THE ATOM
JSR PC,GRBAD1 ;MAKE THE "TO" NODE POINT TO A NODE CONTAINING A,,B
ADD #2,S ;POP OFF LINE WITH VARIABLES IN IT
MOV #LIST,A ;LIST TYPE
BIS A,TOPS ;SET IN THE TYPE
MOV TOPS,B ;GET BACK POINTER TO THE "TO" NODE
SPOP C ;GET POINTER TO NEXT LINE
TST (P)+
RTS PC
;ACCEPTS POINTER TO TOKEN STRING IN C, INCREMENTS C AND LISTIFIES WHAT IT POINTS TO
;PUSHES LIST ON S PDL
LTOK:
ADD @PBASE,C ;MAKE C ABSOLUTE
MOV (C)+,D ;GET THE COUNT
TST (C)+ ;SKIP THE "LINE NUMBER"
SUB @PBASE,C ;MAKE IT REALIVE AGAIN
LTOK1: SPUSH C ;SAVE POINTER
JSR PC,SLISTB ;START LIST BUILDING
ASR D ;INTO WORD COUNT
DEC D ;AND DECREMENT IT
BEQ LTOKDN
LTOKLP: SPOP C ;GET POINTER TO LINE
ADD @PBASE,C ;MAKE C ABSOLUTE
MOV (C)+,B ;GET THE NEXT TOKEN
SUB @PBASE,C ;MAKE IT RELATIVE AGAIN
SPUSH C ;AND PUT IT BACK ON
MOV B,A ;COPY FOR THE TYPE
BIC #7777,A ;CLEAR IT OUT
CMP A,#UFUN ;IS IT A SYSFUN, OR INFIX OPERATOR?
BLO LTOKSY ;SYSTEM FUNCTION
BEQ LTOKUF ;USER FUNCTION
MOV #':,C ;FOR USER VARIABLE
CMP #UVAR,A ;USER VARIABLE?
BEQ LTOKAD ;ADD CHARACTER IN D TO ATOM IN B
MOV #'",C ;ATOM PRINT "
CMP #ATOM,A ;ATOM?
BEQ LTOKAD ;ADD CHARACTER IN D TO ATOM IN B
CMP #LSTR,A ;IS IT ALREADY AN LSTR?
BNE LTOKLT ;NO, MUST BE INUM,FNUM, OR LIST, OKAY AS IS
JSR PC,CHRLST ;ADD " TO THE LSTR
LTOKL1: MOV TOPS,B ;POINTER TO THE NEW LSTR
LTOKL2: MOV #LSTR,A ;IT IS AN LSTR
LTOKLT: JSR PC,LISTB ;BUILD A LIST ELEMENT FROM A,,B
SOB D,LTOKLP ;GO BACK FOR MORE
LTOKDN: JSR PC,FLISTB ;FINISH LIST, AND PUT POINTER TO IT IN B
SPOP C ;RESTORE LINE POINTER
JMP CLRTOP
LTOKSY: JSR PC,LSFUN ;CONVERT THE FUNCTION TO LSTR POINTED TO BY TOPS
BR LTOKL1 ;ADD IT TO THE LIST
LTOKUF: JSR PC,.LOAD ;POINTER TO THE PNAME IN B, TYPE IN A
BR LTOKL2 ;ADD IT TO THE LIST
LTOKAD: JSR PC,CHRATM ;ADD CHARACTER TO PNAME
BR LTOKL1 ;ADD IT TO THE LIST
;APPEND CHARACTER IN C TO BEGINNING OF PNAME OF ATOM POINTED TO BY B
CHRATM: JSR PC,.LOAD ;GET THE POINTER TO PNAME IN B
;DROP INTO CHRLST
;APPEND CHARACTER IN D TO BEGINNING OF PNAME IN B, OUTPUT POINTER IN TOPS
;OUTPUT IS PROTECTED BY TOPS
CHRLST: MOV B,A ;POINTER TO THE REST OF THE PNAME
MOV C,B ;GET THE CHARACTER TO ADD
BIC #170000,A ;CLEAR OUT THE OLD TYPE
BIS #SSTR,A ;AND MAKE IT AN SSTR
JSR PC,GRBAD ;GET A NODE CONTAINING PNAME AND THE SINGLE CHARACTER
BIS #LSTR,C ;SAY IT IS AN LSTR
MOV C,TOPS ;GC-PROTECT IT
RTS PC
;CONVERT SFUN IN B TO AN LSTR, OUTPUT IN TOPS
LSFUN: SPUSH D ;SAVE THE NUMBER OF TOKENS
SPUSH PCHR ;SAVE THE PCHR
JSR PC,BLSTI ;INIT THE LIST BUILD
MOV #BLST,PCHR ;ROUTINE FOR ADDING CHARACTERS TO THE LSTR
MOV B,A ;COPY POINTER FOR PROAB
JSR PC,PROAB ;PRINT THE NAME OF THE FUNCTION
JSR PC,BLSTF ;FINISH THE LSTR
POP PCHR ;PUT BACK PRINT ROUTINE
SPOP D ;GET BACK NUMBER OF TOKENS
RTS PC
CVSFLS: JSR F,CACSAV ;SAVE AC'S
JSR PC,LSFUN ;AND CONVERT IT
JSR F,CACRES ;RESTORE AC'S
RTS PC
.SBTTL ILINE & ERSET STUFF
.GLOBL CURPNT,ERRPNT,LASTER,NLINEL,NPROCL,NTOKEL ;137
ILINE:
MOV #CURPNT,PBASE ;FAKE A BINDING NODE FOR THE CURRENT LINE
MOV #HEADER,C
CLR F
JSR PC,LTOK ;LISTIFY IT
CLZ ;AND RETURN IT
RTS PC
ERRPRO: ;OUTPUT NAME OF PROC EXTENT AT LAST ERROR
MOV NPROCL,B
BEQ ERRPR1
JSR PC,.LOAD
PUSHS B
CLZ
RTS PC
ERRPR1: PUSHS #LSTR
RTS PC
ERRLIN: ;OUTPUT LINE # EXTENT AT LAST ERROR
MOV NLINEL,B
BR NTOKE1
ERRTOK: ;OUTPUT TOKEN # EXTENT AT LAST ERROR
MOV NTOKEL,B
NTOKE1: JMP R1NARG
ERRLOC: ;OUTPUT ADDR OF LAST ERROR
MOV LASTER,B
BR NTOKE1
ERRNUM: ;OUTPUT NO. OF LAST ERROR
MOV ERRPNT,B
CMP (B)+,(B)+
JSR PC,GETERW
BR NTOKE1
ERRNAM: MOV #4,C ;MAX CHARS
MOV ERRPNT,ERRPT
JSR PC,BLSTI ;START AN LSTR
ERRNA2: JSR PC,GETERB
INC ERRPT
TST D
BEQ ERRNA1
JSR PC,BLST
SOB C,ERRNA2 ;CONTINUE UNLESS DONE
ERRNA1: JSR PC,BLSTF
BEQ ERRPR1
PUSHS TOPS
CLZ
RTS PC
.GLOBL BRAKEL ;138
.GLOBL ERSDIS ;139
.GLOBL PBE ;140
ERRBRE: ;OUTPUT BRAKE(U)
MOV BRAKEL,B
BR NTOKE1
ERRSET: JSR PC,GTUOEB
BEQ 1$
ERROR+HNM
1$: MOV B,ERPROC
SEZ
RTS PC
ERRCLE: CLR ERPROC
ERRC3: RTS PC
ERNAME: ;ERASE NAME
JSR PC,GTUOEB
BEQ ERN2
CMP #UFUN,A ;AN SFUN OR INFIX?
BGT 1$
ERROR+ERW
1$: JSR PC,CVSFLS
MOV #ATOM,A
JSR PC,.OBSCH
BEQ ERRC3
ERN2: MOV #VBIND,A
JSR PC,.UNBND
SEZ
RTS PC
.SBTTL ERASE
ERASE: JSR PC,GTUOEB ;GET THE PROCEDURE TO ERASE
BNE ERASE1 ;NOT A UOE, MUST BE A SYSTEM WORD
JSR PC,ERPR ;ERASE THAT PROCEDURE
BEQ 1$
2$: SEZ
RTS PC
1$: TST REDFLG ;IF READING FROM FILE
BNE 2$ ;IGNORE ERASE ERRORS
ERASER: ERROR+PNH ;CAN'T FIND THE STUPID THING
ERASE1: MOV #ERSDIS,A ;POINT TO THE ERASE DISPATCH TABLE
ERASE2: CMP (A)+,B ;IS IT THIS WORD?
BNE 1$ ;NO, SKIP THE ADDRESS
JMP @(A) ;GO DO THAT
1$: TST (A)+ ;PASS THE ADDRESS
TST (A) ;AT THE END OF THE TABLE?
BNE ERASE2 ;NO
ERASE3: ERROR+ERW ;ERASE WHAT?
ERALL: JSR PC,ERALPR ;ERASE ALL THE PROCEDURES
JSR PC,ERALNA ;ERASE ALL THE NAMES
JSR PC,ERARAS ;ERASE ALL THE ARRAYS
JMP TOPLEVEL ;RTS PC FOR NEW SYSTEM
;ERASE LINE
ERL:
ERLINE: TST TOPRNM ;EDITING A PROCEDURE?
BNE 1$ ;YES
ERROR+OIP
1$: JSR PC,GTLN ;GET LINE NUMBER IN B
BEQ ERASE3 ;LOSE LOSE
NEG B ;TO DELETE THIS LINE
JSR PC,ADLN ;DO THE DEED
ERLI1: SEZ
RTS PC
;ERASE PROCEDURE POINTED TO BY THE ATOM IN B
ERPR: BIC #170000,B ;CLEAR OUT THE TYPE
BIS #UFUN,B ;MAKE IT INTO A UFUN
CMP B,TOPRNM ;IS IT THE PROCEDURE BEING EDITED?
BNE ERPR2 ;NO, ALLOW IT TO HAPPEN
ERPR1: ERROR+PBE ;PROCEDURE BEING EDITED
ERPR2: JSR PC,.BINDF ;GET THE BINDING
BEQ ERLI1 ;CAN'T FIND IT, FORGET IT
DELPRO: TST PROSTK(B) ;IS IT REFERENCED ON THE STACK?
BEQ DELIT ;NO, JUST DELETE IT
MOV #-PROCAR,PROTYP(B) ;CHANGE TYPE TO DELETED
MOV (B),C ;POINTER TO THE 2ND WORD OF BINDING NODE
BIC #170000,-(C) ;CLEAR OUT THE TYPE OF THE FIRST WORD
BIS #DBIND,(C) ;SET IN DELETED PROCEDURE BINDING
RTS PC ;AND RETURN
DELIT: SPUSH B ;SAVE B
TST PROTYP(B) ;WAS IT DELETED PREVIOUSLY?
BMI DELHRD ;DELETE IT THE HARD WAY
MOV PROATM(B),B ;GET POINTER TO THE BINDING NODES
MOV #FBIND,A ;DELETE THE FUNCTION BINDING
JSR PC,.UNBND ;DELETE THE BINDING
DELARR: SPOP B ;GET BACK POINTER TO THE ARRAY
JSR PC,.RELES ;RELEASE IT
CLZ
RTS PC
DELHRD: MOV PROATM(B),B ;GET POINTER TO THE BINDING NODES
MOV B,C ;THIS IS THE POINTER TO THE PREVIOUS NODE
MOV B,A ;AND SET UP POINTER TO THE START ALSO
DELOP: MOV C,D ;GET POINTER TO THE PREVIOUS
MOV A,C ;THE NEXT NODE TO LOAD
JSR PC,.LOADC ;LOAD IT UP
CMP B,(P) ;IS IT POINTER TO THE SAME ADDRESS?
BNE DELOP ;NO, TRY TRY AGAIN
MOV A,B ;WHAT THE NODE POINTS TO
BIC #7777,A ;IS IT A DBINDED NODE?
CMP A,#DBIND ;WELL?
BEQ 1$ ;YES, ALL IS WELL
MOV B,A ;RESTORE A
BR DELOP ;AND TRY AGAIN
1$: MOV D,C ;POINTER TO THE NODE BEFORE THIS
JSR PC,.LDP1 ;GET WHAT IT POINTS TO
BIC #7777,A ;GET THE TYPE TO PUT ON THE NEW POINTER
BIC #170000,B ;CLEAR OUT THE POINTER
BIS B,A ;SET IN THE POINTER INTO THE TYPE
JSR PC,.STP1 ;AND CLOBBER THAT NODE TO POINT TO THE NEXT
BR DELARR ;NOW DELETE THE ARRAY
;ERASE ALL PROCEDURES
ERALPR: TST TOPRNM ;ANY BEING EDITED?
BEQ ERALP1 ;NO, CONTINUE
MOV TOPRNM,B ;GET UOE EDITED INTO B
BR ERPR1 ;TO REPORT THE ERROR
ERALP1: JSR PC,GNOLEI ;INITIALIZE THE GET NEXT OBLIST ROUTINE
ERALP2: MOV #FBIND,A ;THE BINDING TO LOOK FOR
JSR PC,GNOLE ;GET THE NEXT OBLIST ELEMENT
BEQ ERLI1 ;RETURN WHEN WE CANT GET ANY MORE
JSR PC,BURYQ ;IS IT BURIED?
;ALSO GETS INDEX TO ARRAY IN B
BEQ ERALP2 ;YES, OR ISN'T A PROCEDURE
JSR PC,DELPRO ;DELETE THE PROCEDURE, IF AT LEVEL 0, OR FIX
;IT TO BE DELETED LATER
BR ERALP2 ;FOR ALL THE PROCEDURES
.GLOBL $ALL,$TOUT,.DELET,.DELI,TF6 ;141
;ERASE ALL NAMES
ERALNA: JSR PC,GNOLEI ;INIT GET NEXT OBLIST ELEMENT
ERALN1: JSR PC,GNOLE ;GET THE NEXT OBLIST ELEMENT
BEQ ERALN2 ;DONE
MOV #VBIND,A ;DELETE VARIABLE BINDINGS
JSR PC,.UNBND
BR ERALN1 ;DELETE THEM ALL
ERALN2: RTS PC
BURY: MOV PC,TF6 ;SET THE FLAG SAYING WE ARE ENABLING THIS FEATURE
BR BURY1 ;GO DO IT
EBURY: CLR TF6 ;CLEAR A FLAG FOR LATER
BURY1: MOV #TPBF,D ;THE FLAG TO CHANGE
BR TRACE2 ;DO IT
STEP: MOV PC,TF6 ;SAY WE ARE TURNING ON STEP
BR STEP1
ESTEP: CLR TF6
STEP1: MOV #TPSF,D ;THE FLAG FOR STEPPING
BR TRACE2
TRACE: MOV PC,TF6
BR TRACE1
ETRACE: CLR TF6 ;CLEAR THE TRACE
TRACE1: MOV #TPTF,D ;THE TRACE FLAG
TRACE2: JSR PC,GTUOEB ;GET THE OBLIST ELEMENT INTO B
BNE TRCSYS ;WASN'T USERS PROC, GET A SYSTEM WORD
JSR PC,CSSTF ;SET THE CORRECT FLAG FOR PROC IN B
BNE TRCDON ;DONE WITH THIS
TRAERR: ERROR+PNH ;NO PROCEDURE TO DO THIS WITH
TRCSYS: CMP #SFUN,A ;IS IT A SYSTEM FUNCTION
BNE TRAERR ;NOPE
.IFNZ ENG
CMP #$ALL,B ;IS IT TRACE ALL?
BEQ TRCALL ;YES
.ENDC
.IFNZ FR
CMP #$TOUT,B ;IS IT TRACE TOUT?
BEQ TRCALL ;YES
.ENDC
ERROR+ERW ;TRACE WHAT?????
TRCALL: JSR PC,GNOLEI ;INIT GET NEXT USER OBLIST ELEMENT
TRCAL1: JSR PC,GNOLE ;GET THE NEXT ELEMENT
BEQ TRCDON ;FINISHED
CMP #TPBF,D ;IS IT AN ERASE BURY?
BEQ TRCAL3 ;YES, DO IT REGARDLESS, ELSE IF PROC'S ARE BURRIED, DONT
;TOUCH THEM
JSR PC,BURYQ ;IS IT BURIED?
BEQ TRCAL1 ;YES, DONT TOUCH THEM
TRCAL2: JSR PC,CSSTF1 ;SET OR CLEAR THE APPROPRIATE FLAG
BR TRCAL1 ;NEXT!!
TRCAL3: JSR PC,CSSTF ;CLEAR THE BURY FLAG
BR TRCAL1
TRCDON: SEZ
RTS PC
;THIS ENTRY SETS OR CLEARS A FLAG IN D, ACCORDING TO TF6, PROC POINTED TO BY UOE IN B
;CSSTF1 DOES THE SAME, EXCEPT WITH POINTER TO PROC IN B
CSSTF: JSR PC,.BINDF ;GET THE FUNCTION BINDING IN B
BEQ TRCDON ;FAILED MISERABLY
CSSTF1: MOV B,A ;GET POINER TO ARRAY INTO A
ADD #HEADER+2,A ;POINT TO THE FLAGS FOR THIS PROC
BIC D,(A) ;CLEAR THE FLAG
TST TF6
BEQ 1$ ;NO, FINE
BIS D,(A) ;WELL SET IT AFTER ALL
1$: CLZ
RTS PC
;THIS RETURNS WITH Z SET IF THE PROCEDURE IS BURRIED, B GETS CLOBBERED TO POINT TO THE
;ARRAY'S ADDRESS
BURYQ: PUSH A
SPUSH B
SPUSH C
JSR PC,.BINDF ;GET THE BINDING IF IT EXISTS
BEQ BURYQ1 ;NO PROCEDURE
MOV B,2(P) ;RETURN THIS POINTER
BURYQ3: BIT #TPBF,HEADER+2(B) ;IS THE BURY BIT ON?
BEQ BURYQ2 ;NO, RETURN WITH Z CLEARED
BURYQ1: JMP RETC
BURYQ2: JMP SRETC
BURYQX: PUSH A
SPUSH B
SPUSH C
JSR PC,.BINDF ;GET THE BINDING
BEQ BURYQ1 ;NO PROCEDURE
BR BURYQ3 ;OTHERWISE DO A PROBLEM
.IF NZ DEBUGR
STRACS: BIT #TRACEF,FLAGS2
BEQ STRA2
SPACE
BR STRA1
STRACE: BIT #TRACEF,FLAGS2 ;SYSTEM TRACE
BEQ STRA2
STRA1: INC NBKTS
PUSH A
PRTXT ^/CT=/
BIC #DPQF,FLAGS2
JSR PC,PRCT
PRTXT ^/ CO=/
JSR PC,PRCO
PRTXT ^/ S=/
BIC #DPQF,FLAGS2
JSR PC,PRS1
PRCR
CLR NBKTS
POP A
STRA2: RTS PC
SETSTF: BIS #TRACEF,FLAGS2 ;SET SYSTEM TRACE FLAG
BR SEZRTS
CLRSTF: BIC #TRACEF,FLAGS2
BR SEZRTS
.ENDC
FLEV: MOV FUNLEV,B ;RETURN USER PROC CALL DEPTH
FLEV1: JMP R1NARG
NODES: ;OUTPUT NO. OF NODES IN FREE STG LIST
MOV NNIFSL,B
BR FLEV1
.SBTTL UTILITY ROUTINES
.GLOBL ALEVN,CTYO1,LVERNF,RNSEED ;144
.GLOBL DEBSW,SECRET,SETTTY,TINECH ;145
.GLOBL .CLOS0,DELTMP,ERRORN,ERTAB,FBUG,RESTTY,SETCH0 ;146
.GLOBL ERRPT,NOADDR,ROTTAB ;147
.GLOBL ERCLR1,ERCLR2 ;148
.GLOBL BRKMOF,DSKERW,ENGDER,MUCWRD,NAME ;149
.GLOBL PPOPL,PPUSHL,SPOPL ;150
.GLOBL PDLEMR,POPLM,PPDLCP,PPEMR,PPLIMT,PSWPAD ;151
.GLOBL SPEMR,SPLIMT,SPOPLM,SSWPAD ;152
.GLOBL SPDLCP ;153
.GLOBL INLEN ;161
.GLOBL LNTB ;162
.GLOBL OOT ;163
.GLOBL BMT,GCBITS ;164
.GLOBL LMT,MKDC,SPMSWP ;165
.GLOBL GCMKL,PALETT,PALMAX ;168
.GLOBL DFLAGS,DSGCF ;169
.GLOBL LUNN,NNGC,NODTOP ;170
.GLOBL EXNODE ;171
VERSN: MOV LVERNF,B
BR RANDO1
RANDOM:
MOV RNSEED,B ;GET OLD SEED
MUL #71275,B ;MUL SEED BY GOOD NUMBER!!
ADD #13713,B ;ADD ANOTHER GOOD NUMBER!! TO LOW ORDER PART
MOV B,RNSEED ;THIS IS THE NEW SEED
MOV B,A
MUL #10.,A ;MULTIPLY IT BY 10
MOV A,B ;HIGH-ORDER PART IS THE DESIRED DIGIT
ADD #5,B
RANDO1: JMP R1NARG
BELL: MOV #7,B
JMP CTYO1
DEBUG: TST ALEVN
BEQ DEBUG1
PRTXTC ^\OFF\
CLR ALEVN
JMP TOPLEVEL
DEBUG1: PRTXTC ^\ON\
MOV #1,ALEVN
BR SEZRTS
SGCF: JSR PC,CKSST
BIS #MGCF,FLAGS2
SEZRTS: SEZ
RTS PC
CGCF: JSR PC,CKSST
BIC #MGCF,FLAGS2
BR SEZRTS
STATUS: BIT #SSF,FLAGS2
BNE STATU2 ;IF ON TURN OFF
JSR PC,TINECH
JSR PC,RDSTR ;READ A STRING
BEQ STATU2 ;EMPTY OR BREAK
MOV @S,B ;SEE IF EQUAL TO "SECRET
MOV #SECRET,C
JSR PC,EQ.TXT
BEQ STATU1 ;NOPE
BIS #SSF,FLAGS2 ;YES
POPS A ;POINTER TO STRING READ IN
PRTXTC ^\ON\
BR STATU3
STATU1: POPS A
STATU2: PRTXTC ^\OFF\
BIC #SSF,FLAGS2
STATU3: JMP SETTTY
CKSST: TST DEBSW
BNE CKSST1
BIT #SSF,FLAGS2
BEQ CKSST9
CKSST1: RTS PC
CKSST9: ERROR+HNM
SPNF: BIS #PNNLF,FLAGS2
BR SEZRTS
CPNF: BIC #PNNLF,FLAGS2 ;CLEAR IT
BR SEZRTS
COMT: .BUG. ;GNT SHOULD SWALLOW ALL COMMENTS;
.SBTTL ERRORS AND HANDLER
EMTBRK: MOV #SRET,(P) ;PRETEND TO FAKE SOMETHING OUT
RTT
ERRBRK:
ERRBK: LDFPS #40300
JSR F,CACSAV ;SAVE THE AC'S
TST REDFLG ;READING?
BEQ ERRBK1 ;NO
.IF NZ FILDSK
JSR PC,SETCH0
JSR PC,.CLOS0 ;GO CLOSE INPUT FILE
.ENDC
TST TOPRNM ;STILL DEFINING A PROCEDURE?
BEQ ERRBK1 ;NOPE
JSR PC,END ;WELL, FINISH IT UP
ERRBK1: CLR GCPREV ;DELETE PENDING WORD AND SENTENCE COMMANDS
.IIF NZ FILDSK, JSR PC,DELTMP ;DELETE THE CAPABILITY TO THE FILE
TST TOPRNM ;DEFINING PROC?
BEQ 1$ ;NO
MOV #'>,PRMTCH ;PROMPT WITH ">"
BR 2$
1$: MOV #'?,PRMTCH ;PROMPT WITH A "?"
2$: JSR PC,RESTTY ;RESTORE THE TTY STATUS
MOV #TYI,GCHR ;GET CHARACTERS FROM THE TTY NOW
MOV #TYO,PCHR ;AND PRINT TO THE TTY
MOV 6*2(P),A ;GET THE TRAP ADDRESS
MOV A,LASTER ;AND SAVE IT
SUB #2,A ;POINT TO THE TRAPPING CALL
JSR PC,GETAML ;GET IN A MEMORY LOCATION POINTED TO BY A
BIC #177600,A ;GET THE TRAP CODE
MOV A,ERRORN ;SAVE THE ERROR NUMBER
ASL A ;TURN IT INTO AN INDEX
MOV ERTAB(A),ERRPNT ;GET THE POINTER TO THE ERROR MESSAGE
CLR NLINEL ;NO ERROR LINE YET
CLR NPROCL ;CLEAR THE PROCEDURE ALSO
MOV BRAKE,BRAKEL ;SAVE THE STATE OF THE BREAK FLAG
TST FUNLEV ;IN A PROCEDURE?
BEQ 3$ ;NOPE
MOV CPP,NPROCL ;THE ERROR PROCEDURE
MOV CPLN,NLINEL ;SAVE THE LINE ERROR CAME FROM
3$: TST ERPROC ;ERROR SET?
BEQ ERRNOT ;NOPE
CMP A,#BUG*2 ;IS IT BUG?
BEQ ERRNOT ;YES, DONT ALLOW ERRSET
CMP A,#FBUG*2 ;SAME WITH FBUG?
BEQ ERRNOT
;FALLS THROUGH TO NEXT PAGE
;FALLS IN HERE
SPUSH BRAKE ;SAVE THIS
CLR BRAKE ;ERROR PROCEDURES DONT RUN UNDER THE SHADOW OF BRAKE
JSR PC,SAVEVL ;SAVE THE STATE OF THE WORLD
PUSH #0 ;MAKE IT LOOK LIKE A PROCEDURE CALL
JSR PC,SAVPPS ;AND SAVE THE PDLS
BIS #1,CPDLP ;SAY PROCEDURE PUSH
BIS #1,CSPDLP ;SAY AND ERRORSET PUSH (NOT NEEDED I THINK)
BIC #DORF,FLAGS ;NOT A DO OR READ FRAME
BIS #ERRF,FLAGS ;SAY WE HAVE AN ERROR!!!!
MOV ERPROC,CO ;MAKE IT THE CURRENT PROCEDURE
CLR ERPROC ;DONT ALLOW THIS TO BE ERRSET YET
JSR PC,PEVAL ;EVALUTATE THE PROCEDURE
BEQ ERRNT1 ;NO OUTPUT, JUST DO WHAT WE WERE GOING TO
JSR PC,PRS1 ;PRINT THE OUTPUT
JSR PC,RESPPS ;RESTORE PDLS
TST (P)+ ;POP NUMBER OF ARGS
JSR PC,RESEVL ;AND RESTORE EVAL
MOV B,FLAGS ;PUT BACK THE FLAGS
BR DEBUGL ;POP OFF EVERYTHING, AND RETURN
ERRNT1: JSR PC,RESPPS ;RESTORE THE PDLS
TST (P)+ ;POP OFF NUMBER OF ARGS
JSR PC,RESEVL ;AND GET BACK EVAL...
MOV B,FLAGS ;RESTORE THE FLAGS
SPOP BRAKE ;GET BACK BRAKE
ERRNOT: TST NOADDR ;ANY PRINT OCTAL ADDRESS?
BNE ERNOT1 ;NO
MOV LASTER,A ;GET THE ERROR ADDRESS
JSR PC,PRONL ;AND PRINT IT
SPACE ;WITH A SPACE
ERNOT1: JSR F,CACRES ;RESTORE THE AC'S
MOV ERRPNT,ERRPT ;GET THE ERROR MESSAGE POINTER
.IFZ NOERTX
ADD #6,ERRPT ;POINT TO THE START OF THE ERROR MESSAGE
.IFNZ ENG&FR
BIT #FRFLG,LANG ;IN FRENCH?
BEQ ERPRLP ;NO
INC ERRPT ;LOOK BACKWARDS FOR THE FIRST ZERO BYTE
1$: JSR PC,GETERB ;GET ERROR BYTE IN D
TSTB D
BNE 1$
INC ERRPT ;WE HAVE BACKED UP OVER THE FRENCH ERROR, NOW PRINT IT
.ENDC
ERPRLP: JSR PC,GETERB ;GET THE NEXT BYTE OF ERROR MESSAGE
INC ERRPT ;POINT TO THE NEXT BYTE
TST D
BEQ DEBUGL ;DONE PRINTING, DO THE RIGHT THING NOW
BLT ERPRL1 ;IS A CONTROL BYTE FOR A ROUTINE TO RUN
JSR PC,TYO ;OUTPUT THE CHARACTER
BR ERPRLP ;AND LOOP BACK
ERPRL1: BIC #177600,D ;IT IS THE WORD OFFSET INTO A TABLE, CLEAR THE SIGN EXTEND
ASL D ;INTO A WORD OFFSET
MOV ROTTAB(D),A ;THE ROUTINE TABLE
INC NBKTS ;PRINT BRACKETS
JSR PC,(A) ;CALL THE ROUTINE
BR ERPRLP ;AND ADVANCE THE POINTER
.IFF
MOV #4,A
1$: JSR PC,GETERB
BEQ 2$
JSR PC,TYO
INC ERRPT
SOB A,1$
2$: CMP ERRORN,#BRK ;IS IT BREAK?
BNE DEBUGL ;NO, IGNORE IT
JMP BRK.R ;PRINT BREAK OR PAUSE
.ENDC
PPLACE: MOV FUNLEV,A ;GET THE LEVEL DEEP
BEQ PPLAC1 ;DONT PRINT IT AT TOP LEVEL
STLANC
ENGINS <CPRTXT ^\AT LEVEL \>
ENDENG
FRINS <CPRTXT ^\AU NIVEAU \>
ENDLAN
JSR PC,PRDN ;PRINT THE LEVEL
STLANC
ENGINS <PRTXT ^\ LINE \>
ENDENG
FRINS <PRTXT ^\ LIGNE \>
ENDLAN
MOV CPLN,A ;GET THE CURRENT LINE NUMBER
JSR PC,PRDN ;AND PRINT IT
STLANC
ENGINS <PRTXT ^\ IN \>
ENDENG
FRINS <PRTXT ^\ DE \>
ENDLAN
MOV CPP,B ;THE CURRENT PROCEDURE NAME
JSR PC,PPNAME ;AND PRINT IT
PPLAC1: JMP .CRLF ;AND PRINT CR-LF
DEBUGL: JSR PC,PPLACE ;PRINT THE PLACE
CLR BRAKE ;NO BREAK
TST ALEVN ;SHOULD WE REALLY ENTER A BREAK LOOP?
BEQ TOPLEVEL ;NOPE, POP AWAY JOE!!
DBUGL1: TST FUNLEV ;TOP LEVEL?
BEQ TOPLEVEL ;YES, JUST FORGET IT
JSR PC,SAVEVL ;SAVE EVAL (AGAIN)
PUSH #0 ;OH WELL, PUSH NUMBER OF ARGS
JSR PC,SAVPPS ;SAVE THE PDLS AGAIN
BIS #1,CPDLP ;SAY THIS IS A PROCEDURE PUSH
BIC #DORF,FLAGS ;NOT DO OR READ FRAME
BIS #ERRF!BRKF,FLAGS ;SAY ERROR, AND BREAK LOOP
JMP MLOOP ;OH WELL, GIVE HIM THE TTY!!!
TOPLEVEL:
TST FUNLEV ;IN A PROCEDURE?
BEQ 1$ ;NO, JUST CLEAN UP OTHER RANDOM FRAMES
MOV #TOPLEVEL,PSTOPR ;KEEP GOING TO TOPLEVEL
JMP PSTOP1 ;AND STOP THIS PROCEDURE
1$: BIT #DORF,FLAGS ;IN A DO OR READ FRAME?
BEQ ERTL3 ;NO, MUST BE AT TOP LEVEL NOW
MOV #1$,DOFRET ;THE PLACE TO RETURN TO
JMP POPVAR ;AND POP THIS FRAME
ERTL3: CLR A ;CLEAR OUT THE PDLS
JSR PC,PPTA ;POP THE P TO THE BASE OF THE STACK
CLR A
JSR PC,PSTA ;POP THE S PDL TO THE BASE OF THE STACK
CLR CSPDLP ;NO PDL OFFSETS
CLR CPDLP
MOV #ERCLR1,A ;THE START OF THE AREA TO CLEAR
MOV #<ERCLR2-ERCLR1>/2,B ;THE LENGTH IN WORDS OF THE AREA TO CLEAR
3$: CLR (A)+ ;CLEAR IT OUT
SOB B,3$
BIC #ERRF+BRKF,FLAGS ;CLEAR ALL SORTS OF RANDOM FLAGS
JMP MLOOP ;AND GO TO TOP LEVEL
FBUGB: BPT ;BREAK ON A FATAL BUG
JMP TOPLEVEL ;TRY TO RECOVER
BRK.R: MOV BRAKE,A ;THE BREAK FLAG
CLR BRAKE ;CLEAR IT
SPUSH MUCWRD ;SAVE THE MUSIC STATUS WORD
.IIF NZ SITS, JSR PC,BRKMOF ;TURN OFF THE MUSIC BOX IF HE HAS IT
SPOP MUCWRD ;AND RESTORE IT
TST A ;IS IT CONTROL-Z?
BLT PAUS.R ;YES
STLANC
ENGINS <PRTXT ^\STOPPED!!\>
ENDENG
FRINS <PRTXT ^\ARRET\>
ENDLAN
JMP DEBUGL ;GO EITHER RETURN TO TOPLEVEL, OR ENTER BREAK LOOP
PAUSE:
PAUS.R: PRTXT ^\PAUSE\
JSR PC,PPLACE ;PRINT THE PLACE
JMP DBUGL1 ;AND ENTER BREAK LOOP
BUG.R: PRTXT ^\HELP!!! LOGO BUG VERSION #\
MOV #VERNF,A ;GET THE VERSION NUMBER
JSR PC,PRDN ;PRINT IT
SPACE ;PRINT A SPACE
TST DEBSW ;BEING DEBUGGED?
BEQ BUGBP1 ;NO
BUGBPT: BPT
BUGBP1: MOV LASTER,A ;GET THE ADDRESS
JSR PC,PRONL ;PRINT IT
JMP DEBUGL ;AND ENTER DEBUG LOOP
CTIT.R: MOV TOPRNM,B ;GET THE PROCEDURE NAME
JMP PPNAME ;AND PRINT IT
HNM.R: MOV B,A ;THE THING THAT HAS NO MEANING
BIC #7777,A ;GET THE TYPE
BIS #DPQF,FLAGS2 ;DONT PRINT " FOR AN ATOM
CMP A,#UFUN ;USER FUNCTION OR SYSTEM FUNCTION
BLOS 1$ ;YES
JMP PRPNM1 ;PRINT THE OTHER
1$: JMP PROAB ;PRINT THE NAME OF THE FUCTION
WTIB.R: MOV B,A ;LINE NUMBER SHOULD BE IN A
JMP PRDN ;AND PRINT IT
TDE.R: MOV E,A ;TERMINAL NUMBER
JMP PRDN ;PRINT THE NUMBER
PAE.R: MOV #UFUN,A ;THE TYPE
MOV TEMP,B ;THE NAME OF THE PROCEDURE
RTS PC ;AND RETURN
WTAA.R: PUSHS A ;PUSH THE OUTPUT
RTS PC
WTAB.R: PUSHS B ;PUSH IT ALSO
RTS PC
NCF.R: MOV TOPS2,A ;WAS THERE A TAG?
BNE 1$
MOV #LSTR,A ;PRINT EMPTY WORD
1$: PUSHS A ;TAG WE WERE LOOKING FOR
RTS PC
.SBTTL MISC ROUTINES
.GLOBL PPSWPO,PPSWPI
CACSAV: JSR PC,PPUSHT ;CAREFUL AC SAVE
ACSAV: MOV E,-(P)
MOV D,-(P)
MOV C,-(P)
MOV B,-(P)
MOV A,-(P)
JMP (F)
CACRES: JSR PC,PPOPT ;CAREFUL AC RESTORE
ACRES: TST (P)+
MOV (P)+,A
MOV (P)+,B
MOV (P)+,C
MOV (P)+,D
MOV (P)+,E
RTS F
PPUSHT: CMP P,PPUSHL
BLOS 1$
RTS PC
1$: JMP PPSWPO ;PDL REALLY OVERFLOWED
PPOPT: CMP P,PPOPL
BHIS 1$
RTS PC
1$: JMP PPSWPI
SPUSHT: SUB #2,S
CMP S,SPUSHL
BLOS 1$
RTS PC
1$: JMP SPSWPO
SPOPT: ADD #2,S
SPOPT1: CMP S,SPOPL
BHI 1$
RTS PC
1$: JMP SPSWPI
.SBTTL P AND S PDL POPPERS
PPTA: ;POP PP PDL TO (A) RELATIVE
;USES A,F
SPOP F
PPTA1: CMP A,PRBAO
BHIS PPTA3
MOV PPOPL,P
JSR PC,PPSWPI
BR PPTA1
PPTA3: SUB PRBAO,A
SUB IP,A
NEG A
CMP A,P
BHIS 1$
ERROR+FBUG ;OVER POPPING
1$: MOV A,P
JSR PC,PPOPT
JMP (F)
PSTA: ;POP S PDL TO (A) RELATIVE
;USES A
CMP A,SPRBAO
BHIS PSTA3
MOV SPOPL,S
JSR PC,SPSWPI
BR PSTA
PSTA3: SUB SPRBAO,A
SUB IS,A
NEG A
CMP A,S
BHIS 1$
ERROR+FBUG ;OVER POPPING
1$: MOV A,S
JMP SPOPT1
MLOOP: JSR PC,GETSTR
JSR PC,MREAD
BEQ MLOOP ;NO TOKEN LIST
JSR PC,EVLINE
BEQ MWDW
BR MLOOP ;LOOP BACK
MWDW: ERROR+WDW ;WHAT SHOULD I DOO WITH (S)
.SBTTL GET A STRING
GETSTR:
GETST0: JSR PC,RDSTR ;GET THE CHARACTERS FOR THE LINE INTO AN LSTR
BNE GETST1 ;GOT SOMETHING
TST RBRKF
BEQ GETST0 ;NOTHING, TRY AGAIN
ERROR+BRK ;ERROR OUT
GETST1: RTS PC
;CURRENT LINE POINTED TO BY A
LINSTP: PUSH GCHR ;SAVE THE PRINTING AND RECIEVING WORLD
SPUSH PCHR
SPUSH PRMTCH ;SAVE THE PROMPT CHARACTER
CLR PRMTCH ;DONT PROMPT AT ALL
MOV #TYI,GCHR ;RECIEVE CHARACTER FROM THE TTY
MOV #TYO,PCHR ;AND PRINT THE LINE THERE
MOV A,F ;GET THE POINTER TO THE CURRENT LINE
JSR PC,PRLN ;AND PRINT IT OUT
JSR PC,RDSTR ;READ A STRING
BEQ LINST1 ;EMPTYP, MIGHT BE A BREAK RECIEVED
POPS A ;IGNORE LINE TYPED IN
LINST2:
POP PRMTCH ;POP PROMPT AND REST OF WORLD
SPOP PCHR
SPOP GCHR
RTS PC
LINST1: TST RBRKF
BEQ LINST2 ;NOPE
POP PRMTCH ;NEED THE PROMPT CHARACTER
ERROR+BRK ;AND ERROR OUT
.SBTTL MORE READ ROUTINES!!!
MREAD:
MREAD1: CLR ILINEL
JSR PC,READ ;CONVERT CHAR STRING TO TOKEN LIST
BEQ MRD4 ;NO TOKENS
POPS A
MOV A,ILINEL ;GC PROTECT THIS CRUFT
JSR PC,WRTLIN ;WRITE LINE INTO THE COMMAND BUFFER
CLZ
MRD4: RTS PC
CKSTG: ;CKECK IF DISC OR NODES ARE ALMOST GONE
BIT #DSAMFL,FLAGS2
BNE CKSTG1
CMP NNIFSL,#NBN
BHIS MRD4
JSR PC,.GCOLL ;GC AND EXPAND IF NEEDED
CMP NNIFSL,#NBN
BHIS MRD4
CKSTG1: CLR ERPROC
ERROR+NSL
;WRITE LINE POINTED TO BY A INTO COMMAND BUFFER
WRTLIN: MOV #CURLIN+4+HEADER,C ;POINTER TO THE CURRENT LINE
CLR D ;COUNTER OF TOKENS
WRTLOP: JSR PC,.LOADA ;GET THE FIRST NODE IN A,,B
MOV B,(C)+ ;WRITE IT INTO THE BUFFER
INC D ;ONE MORE TOKEN
BIT #7777,A ;DONE?
BEQ WRTDON ;YES
CMP D,#INLEN ;HAVE WE DONE ALL OF THEM?
BNE WRTLOP ;NO
;HERE THE BUFFER IS FULL
ERROR+NAS ;NOT ENOUGH ARRAY SPACE (SHOULD BE TOO MANY TOKENS)
WRTDON: INC D ;SO THAT WE HAVE A LINE NUMBER
ASL D ;WANT A BYTE COUNT
MOV D,CURLIN+HEADER ;AND PUT IN THE LENGTH
MOV #HEADER,CTP
MOV #CURPNT,CPBND ;MAKE CPBND POINT TO SOMETHING
;THAT ALWAYS HAS CURLIN
RTS PC
.SBTTL EVAL 1 LINE
;EVAL THE LINE ON THE S PDL,
;IN THE NEW SCHEME, EVAL THE LINE POINTED TO BY CTP
EVLINE:
;THIS IS A SUPER HACK TO MAKE CONTINUE WORK (SORT OF)
TST BRAKE
BEQ 2$
ERROR+BRK
2$:
BIC #EVIFS,FLAGS
CLR CO
CLR NOR
CLR COF
CLR LO
JSR PC,IGNT
EVLI1: BIT #CRF,FLAGS
BNE EVLI2
TST TOPRNM ;IN PROCEDURE?
BNE EVLI4 ;NO, JUST FORGET IT
EVLI6: JSR PC,EVAL
BEQ EVLI3 ;NO OUTPUT, OK
JSR PC,CKSTG
SEZ
RTS PC
EVLI3: JSR PC,CKSTG
BIT #CRF,FLAGS
BNE EVLI2
JSR PC,GNT
BIS #RTF,FLAGS
BR EVLI1
EVLI4: BIC #7777,A
CMP #SNUM,A
BEQ EVLI5 ;AN SNUM
CMP #INUM,A
BEQ EVLI8 ;AN INUM
CMP #LSTR,A
BNE EVLI6 ;NOT AN SNUM, INUM OR LSTR
JSR PC,.CLSIN ;CONVERT LSTR TO INUM
BEQ EVLI6 ;NOT NO. OR TOO BIG
EVLI8: BIT #SPDF,FLAGS ;IS THIS PROC DEF. BEING SKIPPED?
BNE EVLI2
JSR PC,.CINSN ;CONVERT INUM TO SNUM
BEQ EVLI7 ;TOO BIG
TST B ;IS NO. TOO SMALL?
BGT 1$
ERROR+LNTB
1$: BIC #RTF,FLAGS ;DONT WANT TO REPEAT THIS TOKEN
EVLI5: JSR PC,ADLN
EVLI2: CLZ
RTS PC
EVLI7: ERROR+LNTB ;LINE # TOO BIG
.SBTTL GET NEXT TOKEN
GNT: MOV CT,B ;GET THE OLD CURRENT TOKEN
BIT #RTF,FLAGS ;SHOULD WE REPEAT THIS TOKEN
BEQ GNT1 ;NO
BIC #RTF,FLAGS ;CLEAR THE FLAG
TST B ;END OF LINE?
BNE 1$ ;NO
BIS #CRF,FLAGS ;SAY IT IS
1$: MOV B,A ;COPY IT
RTS PC
GNT1: BIC #PTLPF,FLAGS ;SET FLAG FOR PARENS
CMP #$LLPAR,B ;IS IT "!("
BEQ GNTPAR ;YES, OKAY
CMP #$LPAR,B ;IS IT "("
BNE GNT3 ;NO, LEAVE THE FLAG CLEAR
GNTPAR: BIS #PTLPF,FLAGS ;SET THE PARENS FLAG
GNT3: DEC CLCNT ;DECREMENT THE NUMBER OF TOKENS LEFT ON THIS LINE
BMI GNT2 ;DONE WITH THIS LINE
MOV CTP,A ;GET THE NEXT TOKEN POINTER
ADD @CPBND,A ;MAKE IT UNRELATIVE
MOV (A)+,B ;GET THE TOKEN
ADD #2,CTP ;POINT TO THE NEXT TOKEN
CMP #$COMT,B ;IS IT A COMMENT
BEQ SKPCOM ;SKIP THE COMMENT
GNT4: MOV B,CT ;PUT THE TOKEN INTO CT
MOV B,A ;COPY IT FOR SOME APPLICATIONS
RTS PC
GNT2: BIT #CRF,FLAGS ;AT THE END OF LINE THE TIME BEFORE?
BNE 1$ ;YES, LOSER
BIS #CRF,FLAGS ;SAY AT END OF LINE
CLR B ;SAY NO MORE TOKENS
BR GNT4 ;FINISH UP
1$: ERROR+OOT ;OUT OF TOKENS
SKPCOM: DEC CLCNT ;GET THE NEXT TOKEN
BMI GNT2 ;END OF LINE
MOV (A)+,B ;GET THE NEXT TOKEN
ADD #2,CTP
CMP #$COMT,B ;IS IT A COMMENT?
BNE SKPCOM ;NO, JUST CONTINUE
BR GNT3 ;GET THE NEXT TOKEN
IGNT: MOV CTP,B ;POINTER TO THE START OF THE LINE
ADD #4,CTP ;POINT TO THE FIRST TOKEN IN THE LINE
ADD @CPBND,B ;MAKE IT ABSOLUTE
BIC #CRF,FLAGS ;CLEAR THE END OF LINE FLAG
MOV (B),A ;GET THE NUMBER OF TOKENS IN THIS LINE
ASR A ;FROM BYTES TO WORDS
DEC A ;FOR THE LINE NUMBER
MOV A,CLCNT ;SET UP THE TOKEN COUNT
BEQ GNT2 ;SIGNAL END OF LINE IMEDIATELY
BIS #RTF,FLAGS ;REPEAT THIS TOKEN
BR GNT3 ;CONTINUE WITH THE REST OF THE LINE.
.SBTTL GARBAGE COLLECTOR
MARKNI: SPUSH A
SPUSH B
BR MARKN4
MARKN: SPUSH A ;MARK NODE(B)
SPUSH B
;DEBUGGING FEATURE
JSR PC,.LOAD ;ARE WE MARKING AN IDLE NODE
BIC #7777,A
CMP #IDLE,A
BNE 1$
.BUG.
1$: MOV (P),B
;
MARKN4: MOV B,A
BIC #170000,A
BIC #177770,B
MOVB BMT(B),B
ASH #-3,A
ADD GCBITS,A
BITB B,(A) ;ALREADY MARKED?
BEQ MARKN1 ;NO
MARKN3: SPOP B
SPOP A
SEZ
RTS PC
MARKN1: BISB B,(A)
MARKN2: SPOP B
SPOP A
CLZ
RTS PC
MARKDN: ;SKIP IF NODE (B) IS MARKED
SPUSH A
SPUSH B
MOV B,A
BIC #170000,A
BIC #177770,B
MOVB BMT(B),B
ASH #-3,A
ADD GCBITS,A
BITB B,(A) ;MARKED?
BEQ MARKN3 ;NO
BR MARKN2 ;YES-SKIP
MARKL: PUSH A ;MARK LIST
SPUSH B ;NODE ADDS IN B
SPUSH C
JSR PC,MKLIST
BR MARKV1
MARKV: PUSH A ;MARK VARIABLE
SPUSH B ;NODE ADDS IN B
SPUSH C
CLR A
MOV B,C
JSR PC,MARKF1 ;TREAT POINTER AS A FIRST PTR
MARKV1: SPOP C
SPOP B
POP A
MARKV2: RTS PC
MARKF: MOV A,C ;MARK FIRST OF A DATUM (NODE) IN A,,B
MARKF1: BIT #DSAMFL,FLAGS2
BEQ MARKF2 ;DISK NOT ALMOST FULL
.GLOBL MKSPSW
JSR PC,MKSPSW
CLR ERPROC
.IFNZ NDISP
ADD #2,S ;POP SNLIST OFF S PDL
.ENDC
ERROR+NSL
MARKF2: ASH #-11.,C
BIC #177741,C ;GET THE DATA TYPE
JMP @LMT(C) ;WHICH YOU MIGHT MARK ON
.IFNZ NDISP
MKSNAP: JSR PC,MKDC ;MARK DISPLAY CODE
.ENDC
MKLIST: BIT #7777,B ;IS THIS NODE REALLY HERE?
BEQ MARKV2 ;NO. RETURN
MKL1: PUSH A ;SAVE BUTFIRST OF CURRENT (I.E. PARENT) NODE
JSR PC, MARKN ;MARK NEXT NODE
BEQ MKL2
JSR PC,.LOAD ;GET NEXT NODE
JSR PC,MARKF ;MARK FIRST OF NEW NODE
JSR PC,MARKBF ;MARK BUTFIRST OF NEWTHIS NODE
MKL2: POP A
RTS PC
MKATOM: ;MARK ATOM CELL BUT NOTHING INSIDE IT
MKINUM: JMP MARKNI
GCDIE: ERROR+FBUG
MARKBF: BIT #7777,A ;MARK BUTFIRST OF LIST
BEQ MARKV2 ;AT END OF LIST
MKBF1: MOV A,B
JSR PC, MARKN ;MARK NEXT NODE
BEQ MARKV2 ;ALREADY MARKED, QUIT
JSR PC,.LOAD ;GET NEXT NODE
JSR PC,MARKF ;MARK FIRST OF NEW NODE
BR MARKBF ;MARK BUTFIRST OF NEW NODE
GCOLL:
.GCOLL: JSR F,ACSAV
.IF NZ METERS
SPUSH METERP
MOV #MTGCOL,METERP
TST MTFLAG
BNE 1$
INC MTGCCN
1$:
.ENDC
PUSH GNCN
SPUSH GNCN+2
SPUSH TMPBLK
JSR PC,LSBITM ;ON THE LSI IT MAY BE NESSECARY TO MAP IN THE BIT TABLE
.GCOL2: MOV GCBITS,A ;GARBAGE COLLECT
MOV #GCBTL/2,B ;CLEAR BIT TABLE
.GCOL1: CLR (A)+
SOB B,.GCOL1
;NOW MARK EVERYTHING POINTED BY OBLIST. DONT MARK OBLIST NODES YET
JSR PC,GNOLEI
MKUOBJ: JSR PC,GNOLE ;GET NEXT UOE PTR
BEQ MKTPS
MOV B,C
JSR PC,.LOADC ;GET THE NODE
MOV A,C
MKUOE: BIT #7777,C ;ONE OTHER NODE?
BEQ MKUOBJ ;NO
MOV C,B ;YES
JSR PC,MARKN ;MARK IT
JSR PC,.LOADC
MOV A,C
BIC #7777,A
CMP #FBIND,A
BEQ MKFB ;FUNCTION BINDING
CMP #VBIND,A
BEQ MKVB ;VARIABLE BINDING
CMP #ABIND,A
BEQ MKARR
CMP #SVBIND,A
BEQ MKSVB ;SWAPPED VB
CMP #DBIND,A ;DELETED PROC BINDING?
BEQ MKFB ;MARK LIKE REGULAR PROCEDURE BINGING
ERROR+FBUG ;BUG
MKVB: JSR PC,MARKV ;MARK VARIABLE
BR MKUOE
MKSVB: BR MKUOE
MKARR: TSTB 5(B) ;IS IT A POINTER ARRAY?
BNE MKUOE
MOV B,F ;POINT TO BEG OF ARRAY
MOV 2(B),-(P) ;PUSH COUNT
SUB #HEADER,(P)
ASR (P)
ADD #HEADER,F
MKAR1: MOV (F)+,B
JSR PC,MARKV
DEC (P)
BNE MKAR1
TST (P)+
BR MKUOE
MKFB: SPUSH C ;POINTS TO NEXT BINDING
SPUSH E ;USED BY GNOLE
MOV PROEND(B),F ;THE END OF THE PROCEDURE
ADD B,F ;MAKE IT ABSOLUTE POINTER
MOV B,D ;POINTER TO THE START OF THE PROCEDURE
ADD #HEADER,D ;POINT TO THE FIRST LINE OF THE PROCEDURE
MOV D,E ;SHOULD BE POINTER TO START OF NEXT LINE
MKLINE: CMP D,F ;AT THE END OF THE PROCEDURE?
BEQ MKFBD ;YES, JUST CONTINUE WITH NEXT BINDING
BHI MKFBUG ;BUGGY IF WE ARE PAST IT
ADD (E)+,E ;POINT TO THE START OF THE NEXT LINE
ADD #4,D ;POINT TO THE START OF THE ELEMENTS FOR THIS LINE
MKNTOK: CMP D,E ;ARE WE AT THE END OF THIS LINE?
BEQ MKLINE ;YES, TRY THE NEXT LINE
BHI MKFBUG ;ERROR IF WE ARE BEYOND THIS POINT
MOV (D)+,B ;GET THE VARIABLE TO MARK
MOV B,C ;COPY IT FOR THE TYPE
JSR PC,MARKF1 ;MARK THE FIRST OF IT (THE WHOLE TOKEN)
BR MKNTOK ;NEXT TOKEN
MKFBD: SPOP E ;POINTER TO NEXT OBLIST ELEMENT
SPOP C
BR MKUOE ;MARK THE NEXT BINDING FOR THIS ATOM
MKFBUG: ERROR+FBUG
;MARK FROM GCMKL LIST
MKTPS: MOV #GCMKL,F
MKRNDM: MOV (F)+,B ;POINTER TO POINTER
BEQ MKSPDL ;LAST ONE
MOV (B),B ;REAL NODE ADDRESS
BEQ MKRNDM ;NOTHING THERE
BIT #170000,B ;IS TYPE FIELD BLANK
BEQ MKRND1 ;YES, MAKE IT LIKE LIST
JSR PC,MARKV ;MARK VARIABLE
BR MKRNDM
MKRND1: JSR PC,MKL1
BR MKRNDM
MKSPDL: MOV IS,E
MKSP1: MOV -(E),B ;GET A S PDL WORD
CMP E,S ;END OF S PDL?
BLO MKSP2 ;YES
JSR PC,MARKV ;MARK S PDL WORD
BR MKSP1
.GLOBL MKSSP
MKSP2: JSR PC,MKSSP ;MARK THE SWAPPED PART OF THE S PDL
.IFNZ COLOR
MKPALETTE: ;Mark the palette.
MOV #PALETTE, E
MOV #PALMAX, F
MKPALUP:
MOV (E)+, B
JSR PC, MARKV
SOB F, MKPALUP
.ENDC
;OK, NOW MARK ALL UOE'S THAT POINT TO FUNCION OR VARIABLE BINDING
JSR PC,GNOLEI
MKOBL: JSR PC,GNOLE ;GET NEXT UOE PTR IN B
BEQ MKOBL6 ;NONE LEFT
MOV B,C
JSR PC,.LOADC ;GET THE PNAME NODE
MOV B,D
BIT #7777,A ;DOES IT POINT TO ANYTHING?
BNE MKOBL2 ;YES, MARK IT
MOV C,B ;NO WAS IT MARKED?
JSR PC,MARKDN
BEQ MKOBL3 ;NO - LINK IT OUT
BR MKOBL7 ;YES - ALSO MARK PNAME & BUCKET PTR
MKOBL2: ; - MARK THE UOE ETC.
MOV C,B ; -THE UOE NODE
JSR PC,MARKN
MKOBL7: MOV D,B ; -THE PNAME LSTR
JSR PC,MARKL
MOV GNCN+2,B ; -THE BUCKET LIST NODE
JSR PC,MARKN
BR MKOBL
;THIS UOE IS NOT MARKED AND POINTS TO NOTHING - LINK IT OUT
MKOBL3: MOV TMPBLK,C ;GET PTR TO PREDECESSOR NODE
BNE MKOBL4 ;NONE, SO UHCT WAS PRED.
MOV GNCN,-2(E) ;SO CHANGE IT
BR MKOBL5
MKOBL4: MOV GNCN,A ;CHANGE PTR IN PRED NODE
JSR PC,.STP1
MKOBL5: MOV C,GNCN+2 ;SO GNOLE WILL WORK
BR MKOBL
MKOBL6:
.IFNZ NDISP
BIT #DISPF,DFLAGS ;IF GUY HAS DISPLAY
BEQ GCDIS2
JSR PC,DSGCF ;GCOLL IT, TOO
GCDIS2:
GCDIS:
.ENDC
;FALLS THROUGH
;FALLS IN
;OK NOW RETURN ALL IN MARKED NODES
;RA ADDS OF LIT MAP
;RB NODE ADDS
;RC ACTUAL ADDER OF NODE
;RD BIT MAP
;RE POINT TO LIST OF FREE STORAGE RECYCLED NODES
;RF NUMBER NODES LEFT TO CHECK
;START COLLECTING AT LUNN(LOWEST UNPROTECTED NODE #)
CLR E
CLR NNGC
MOV #NODESP,C ;NODE ZERO ADDRESS
MOV NODTOP,F
SUB C,F ;COMPUTE LEGNTH OF NODESP
ASR F
ASR F ;COMPUTE NUMBER OF NODES
CLR B ;NODE ZERO
MOV GCBITS,A ;BIT TABLE ADDR
GCRT2A: MOV (A)+,D ;GET NEXT WORD OF BIT MAP
SEC
ROR D
GCRT2: BCS GCRT3
CMP B,#LUNN
BLOS GCRT3
TST E ;WE HAVE A FREE NODE; IS FIRST FREE FOUND?
BNE GCRT2B
MOV B,FREE ;NO, THIS IS IT
BR GCRT2C ;(NO LAST-FREE TO UPDATE)
GCRT2B: BIS B,(E) ;ELSE: ,E ;THIS NODE IS NEW LAST-FREE
GCRT2C: MOV C,E
MOV #IDLE,(C)+ ;MAKE NEW IDLE NODE, POINTS NOWHERE
CLR (C)+
INC NNGC
BR GCRT4
GCRT3: CMP (C)+,(C)+
GCRT4: INC B
DEC F
BLE GCRT5
CLC
ROR D
BNE GCRT2
BR GCRT2A
GCRT5: MOV NNGC,NNIFSL
;DEBUGGING FEATURE
BIT #PNNLF,FLAGS2
BEQ GCRT6
CPRTXT ^/[NODES LEFT /
MOV NNGC,A
JSR PC,PRDN
PRTXTC ^/ ]/
;
GCRT6:
GCRT7: POP TMPBLK
SPOP GNCN+2
SPOP GNCN
CMP NNIFSL,#200. ;LESS THAN A BLOCK LEFT
BHIS 1$
MOV NODTOP,-(P) ;SAVE OLD NODTOP
JSR PC,EXNODE ;EXPAND NODE SPACE
MOV (P)+,A
MOV A,B
SUB NODTOP,A
BEQ 1$ ;NOTHING ADDED
NEG A
ASH #-2,A ;NUMBER OF NODES ADDED
ADD A,NNIFSL
ADD A,NNGC
MOV B,C ;OLD NODTOP
SUB #NODESP,B
ASH #-2,B ;NUMBER OF FIRST NODE ADDED
MOV FREE,-(P)
MOV B,FREE
INC B
3$: MOV B,(C)
2$: BIS #IDLE,(C)+
CLR (C)+
INC B
SOB A,3$
SUB #4,C
MOV (P)+,(C)
BIS #IDLE,(C)
1$:
.IIF NZ METERS, POP METERP
JSR F,ACRES
SEZ
RTS PC
.SBTTL GET NEXT OBLIST ELEMENT
GNOLE: ;GET NEXT USER OBLIST ELEMENT - PTR
;INPUT - VIA GNOLEI
;OUTPUT - PTR TO THIS BUCKET IN B & GNCN
; " " NEXT " " GNCN+2
; " " PRED " " TMPBLK
; IF NO PREV BUCKET, TMPBLK = 0
;USES E. SKIPS UNTIL NO UOE PTRS LEFT
PUSH A
MOV GNCN,B
MOV GNCN+2,TMPBLK
GNOLE2: MOV B,GNCN+2
BIC #170000,B
BEQ GNOLE1
JSR PC,.LOAD ;GET NEXT PTR ON BUCKEN LIST
MOV A,GNCN
JMP SRETA
GNOLE1: CLR TMPBLK
MOV (E)+,B ;GET NEXT BUCKET LIST
BGE GNOLE2
JMP RETA ;DONE
GNOLEI: MOV #UHCT,E
CLR GNCN
RTS PC