+
+TITLE GETPUT ASSOCIATION FUNCTIONS FOR MUDDLE
+
+RELOCATABLE
+
+.INSRT MUDDLE >
+
+; COMPONENTS IN AN ASSOCIATION BLOCK
+
+ITEM==0 ;ITEM TO WHICH INDUCATOR APPLIES
+VAL==2 ;VALUE
+INDIC==4 ;INDICATOR
+NODPNT==6 ;IF NON ZERO POINTS TO CHAIN
+PNTRS==7 ;POINTERS NEXT (RH) AND PREV (LH)
+
+ASOLNT==8 ;NUMBER OF WORDS IN AN ASSOCIATION BLOCK
+
+.GLOBAL ASOVEC ;POINTER TO HASH VECTOR IN TV
+.GLOBAL ASOLNT,ITEM,INDIC,VAL,NODPNT,NODES,IPUTP,IGETP,PUT,IFALSE
+.GLOBAL DUMNOD,IGETLO,IBLOCK,MONCH,RMONCH,IPUT,IGETL,IREMAS,IGET
+.GLOBAL NWORDT,CIGETP,CIGTPR,CIPUTP,CIREMA,MPOPJ,PVSTOR,SPSTOR
+
+MFUNCTION GETP,SUBR,[GETPROP]
+
+ ENTRY
+
+IGETP: PUSHJ P,GETLI
+ JRST FINIS ; NO SKIP, LOSE
+ MOVSI A,TLOCN
+ HLLZ 0,VAL(B)
+ PUSHJ P,RMONCH ; CHECK MONITOR
+ MOVE A,VAL(B) ;ELSE RETURN VALUE
+ MOVE B,VAL+1(B)
+CFINIS: JRST FINIS
+
+; FUNCTION TO RETURN LOCATIVE TO ASSOC
+
+MFUNCTION GETPL,SUBR
+
+ ENTRY
+
+IGETLO: PUSHJ P,GETLI
+ JRST FINIS
+ MOVSI A,TLOCN
+ JRST FINIS
+
+GETLI: PUSHJ P,2OR3 ; GET ARGS
+ PUSHJ P,IGETL ;SEE IF ASSOCIATION EXISTS
+ SKIPE B
+ AOS (P) ; WIN RETURN
+ CAMGE AB,[-4,,0] ; ANY ERROR THING
+ JUMPE B,CHFIN ;IF 0, NONE EXISTS
+ POPJ P,
+
+CHFIN: PUSH TP,4(AB)
+ PUSH TP,5(AB)
+ MCALL 1,EVAL
+ POPJ P,
+
+; COMPILER CALLS TO SOME OF THESE
+
+CIGETP: SUBM M,(P) ; FIX RET ADDR
+ PUSHJ P,IGETL ; GO TO INTERNAL
+ JUMPE B,MPOPJ
+ MOVSI A,TLOCN
+MPOPJ1: SOS (P) ; WINNER (SOS BECAUSE OF SUBM M,(P))
+MPOPJ: SUBM M,(P)
+ POPJ P,
+
+CIGTPR: SUBM M,(P)
+ PUSHJ P,IGETL
+ JUMPE B,MPOPJ
+ MOVE A,VAL(B) ; GET VAL TYPE
+ MOVE B,VAL+1(B)
+ JRST MPOPJ1
+
+CIPUTP: SUBM M,(P)
+ PUSH TP,-1(TP) ; SAVE VAL
+ PUSH TP,-1(TP)
+ PUSHJ P,IPUT ; DO IT
+ POP TP,B
+ POP TP,A
+ JRST MPOPJ
+
+CIREMA: SUBM M,(P)
+ PUSHJ P,IREMAS ; FLUSH IT
+ JRST MPOPJ
+
+; CHECK PUT/GET PUTPROP AND GETPROP ARGS
+
+2OR3: HLRE 0,AB
+ ASH 0,-1 ; TO -# OF ARGS
+ ADDI 0,2 ; AT LEAST 2
+ JUMPG 0,TFA ; 1 OR LESS, LOSE
+ AOJL 0,TMA ; 4 OR MORE, LOSE
+ MOVE A,(AB) ; GET ARGS INTO ACS
+ MOVE B,1(AB)
+ MOVE C,2(AB)
+ MOVE D,3(AB)
+ POPJ P,
+
+; INTERNAL GET
+
+IGET: PUSHJ P,IGETL ; GET LOCATIVE
+ JUMPE B,CPOPJ
+ MOVE A,VAL(B)
+ MOVE B,VAL+1(B)
+ POPJ P,
+
+; FUNCTION TO MAKE AN ASSOCIATION
+
+MFUNCTION PUTP,SUBR,[PUTPROP]
+
+ ENTRY
+
+IPUTP: PUSHJ P,2OR3 ; GET ARGS
+ JUMPN 0,REMAS ; REMOVE AN ASSOCIATION
+ PUSH TP,4(AB) ; SAVE NEW VAL
+ PUSH TP,5(AB)
+ PUSHJ P,IPUT ; DO IT
+ MOVE A,(AB) ; RETURN NEW VAL
+ MOVE B,1(AB)
+ JRST FINIS
+
+REMAS: PUSHJ P,IREMAS
+ JRST FINIS
+
+IPUT: SKIPN DUMNOD+1 ; NEW DUMMY NEDDED?
+ PUSHJ P,DUMMAK ; YES, GO MAKE ONE
+IPUT1: PUSHJ P,IGETI ;SEE IF THIS ONE EXISTS
+
+ JUMPE B,NEWASO ;JUMP IF NEED NEW ASSOCIATION BLOCK
+CLOBV: MOVE C,-5(TP) ; RET NEW VAL
+ MOVE D,-4(TP)
+ SUB TP,[6,,6]
+ HLLZ 0,VAL(B)
+ MOVSI A,TLOCN
+ PUSHJ P,MONCH ; MONITOR CHECK
+ MOVEM C,VAL(B) ;STORE IT
+ MOVEM D,VAL+1(B)
+CPOPJ: POPJ P,
+
+; HERE TO CREATE A NEW ASSOCIATION
+
+NEWASO: MOVE B,DUMNOD+1 ; GET BALNK ASSOCIATION
+ SETZM DUMNOD+1 ; CAUSE NEW ONE NEXT TIME
+
+
+;NOW SPLICE IN CHAIN
+
+ JUMPE D,PUT1 ;NO OTHERS EXISTED IN THIS BUCKET
+ HRLZM C,PNTRS(B) ;CLOBBER PREV POINTER
+ HRRM B,PNTRS(C) ;AND NEXT POINTER
+ JRST .+2
+
+PUT1: HRRZM B,(C) ;STORE INTO VECTOR
+ HRRZ C,NODES+1
+ HRLM C,NODPNT(B)
+ MOVE D,NODPNT(C)
+ HRRZM B,NODPNT(C)
+ HRRM D,NODPNT(B)
+ HRLM B,NODPNT(D)
+ MOVEI C,-3(TP) ;COPY ARG POINTER
+ MOVSI A,-4 ;AND COPY POINTER
+
+PUT2: MOVE D,(C) ;START COPYING
+ MOVEM D,@CLOBTB(A)
+ ADDI C,1
+ AOBJN A,PUT2 ;NOTE *** DEPENDS ON ORDER IN VECTOR ***
+
+ JRST CLOBV
+
+;HERE TO REMOVE AN ASSOCIATION
+
+IREMAS: PUSHJ P,IGETL ;LOOK IT UP
+ JUMPE B,CPOPJ ;NEVER EXISTED, IGNORE
+ HRRZ A,PNTRS(B) ;NEXT POINTER
+ HLRZ E,PNTRS(B) ;PREV POINTER
+ SKIPE A ;DOES A NEXT EXIST?
+ HRLM E,PNTRS(A) ;YES CLOBBER ITS PREV POINTER
+ SKIPN D ;SKIP IF NOT FIRST IN BUCKET
+ MOVEM A,(C) ;FIRST STORE NEW ONE
+ SKIPE D ;OTHERWISE
+ HRRM A,PNTRS(E) ;PATCH NEXT POINTER IN PREVIOUS
+ HRRZ A,NODPNT(B) ;SEE IF MUST UNSPLICE NODE
+ HLRZ E,NODPNT(B)
+ SKIPE A
+ HRLM E,NODPNT(A) ;SPLICE
+ JUMPE E,PUT4 ;FLUSH IF NO PREV POINTER
+ HRRZ C,NODPNT(E) ;GET PREV'S NEXT POINTER
+ CAIE C,(B) ;DOES IT POINT TO THIS NODE
+ .VALUE [ASCIZ /:\eFATAL PUT LOSSAGE/]
+ HRRM A,NODPNT(E) ;YES, SPLICE
+PUT4: MOVE A,VAL(B) ;RETURN VALUE
+ SETZM PNTRS(B)
+ MOVE B,VAL+1(B)
+ POPJ P,
+
+
+;INTERNAL GET FUNCTION CALLED BY PUT AND GET
+; A AND B ARE THE ITEM
+;C AND D ARE THE INDICATOR
+
+IGETL: PUSHJ P,IGETI
+ SUB TP,[4,,4] ; FLUSH CRUFT LEFT BY IGETI
+ POPJ P,
+
+IGETI: PUSHJ P,LHCLR
+ EXCH A,C
+ PUSHJ P,LHCLR
+ EXCH C,A
+ PUSH TP,A
+ PUSH TP,B
+ PUSH TP,C ;SAVE C AND D
+ PUSH TP,D
+ XOR A,B ; BUILD HASH
+ XOR A,C
+ XOR A,D
+ TLZ A,400000 ; FORCE POS A
+ HLRZ B,ASOVEC+1 ;GET LENGTH OF HASH VECTOR
+ MOVNS B
+ IDIVI A,(B) ;RELATIVE BUCKET NOW IN B
+ HRLI B,(B) ;IN CASE GC OCCURS
+ ADD B,ASOVEC+1 ;POINT TO BUCKET
+ MOVEI D,0 ;SET FIRST SWITCH
+ SKIPN A,(B) ;GET CONTENTS OF BUCKET (DONT SKIP IF EMPTY)
+ JRST GFALSE
+
+ MOVSI 0,TASOC ;FOR INTGOS, MAKE A TASOC
+ MOVE PVP,PVSTOR+1
+ HLLZM 0,ASTO(PVP)
+
+IGET1: GETYPF 0,ITEM(A) ;GET ITEMS TYPE
+ MOVE E,ITEM+1(A)
+ CAMN 0,-3(TP) ;COMPARE TYPES
+ CAME E,-2(TP) ;AND VALUES
+ JRST NXTASO ;LOSER
+ GETYPF 0,INDIC(A) ;MOW TRY INDICATORS
+ MOVE E,INDIC+1(A)
+ CAMN 0,-1(TP)
+ CAME E,(TP)
+ JRST NXTASO
+
+ SKIPN D ;IF 1ST THEN
+ MOVE C,B ;RETURN POINTER IN C
+ MOVE B,A ;FOUND, RETURN ASSOCIATION
+ MOVSI A,TASOC
+IGRET: MOVE PVP,PVSTOR+1
+ SETZM ASTO(PVP)
+ POPJ P,
+
+NXTASO: MOVEI D,1 ;SET SWITCH
+ MOVE C,A ;CYCLE
+ HRRZ A,PNTRS(A) ;STEP
+ JUMPN A,IGET1
+
+ MOVSI A,TFALSE
+ MOVEI B,0
+ JRST IGRET
+
+GFALSE: MOVE C,B ;PRESERVE VECTOR POINTER
+ MOVSI A,TFALSE
+ SETZB B,D
+ JRST IGRET
+
+; FUNCTION TO DO A PUT AND ALSO ADD TO THE NODE FOR THIS GOODIE
+
+REPEAT 0,[
+MFUNCTION PUTN,SUBR
+
+ ENTRY
+
+ CAML AB,[-4,,0] ;WAS THIS A REMOVAL
+ JRST PUT
+
+ PUSHJ P,IPUT ;DO THE PUT
+ SKIPE NODPNT(C) ;NODE CHAIN EXISTS?
+ JRST FINIS
+
+ PUSH TP,$TASOC ;NO, START TO BUILD
+ PUSH TP,C
+ SKIPN DUMNOD+1 ; FIX UP DUMMY?
+ PUSHJ P,DUMMAK
+CHPT: MOVE C,$TCHSTR
+ MOVE D,CHQUOTE NODE
+ PUSHJ P,IGETL
+ JUMPE B,MAKNOD ;NOT FOUND, LOSE
+NODSPL: MOVE C,(TP) ;HERE TO SPLICE IN NEW NODE
+ MOVE D,VAL+1(B) ;GET POINTER TO NODE STRING
+ HRRM D,NODPNT(C) ;CLOBBER
+ HRLM B,NODPNT(C)
+ SKIPE D ;SPLICE ONLY IF THERE IS SOMETHING THERE
+ HRLM C,NODPNT(D)
+ MOVEM C,VAL+1(B) ;COMPLETE NODE CHAIN
+ MOVE A,2(AB) ;RETURN VALUE
+ MOVE B,3(AB)
+ JRST FINIS
+
+MAKNOD: PUSHJ P,NEWASO ;GENERATE THE NEW ASSOCIATION
+ MOVE A,@CHPT ;GET UNIQUE STRING
+ MOVEM A,INDIC(C) ;CLOBBER IN INDIC
+ MOVE A,@CHPT+1
+ MOVEM A,INDIC+1(C)
+ MOVE B,C ;POINTER TO B
+ HRRZ C,NODES+1 ;GET POINTER TO CHAIN OF NODES
+ HRRZ D,VAL+1(C) ;SKIP DUMMY NODE
+ HRRM B,VAL+1(C) ;CLOBBER INTO CHAIN
+ HRRM D,NODPNT(B)
+ SKIPE D ;SPLICE IF ONLY SOMETHING THERE
+ HRLM B,NODPNT(D)
+ HRLM C,NODPNT(B)
+ MOVSI A,TASOC ;SET TYPE OF VAL TO ASSOCIATION
+ MOVEM A,VAL(B)
+ SETZM VAL+1(B)
+ JRST NODSPL ;GO SPLICE ITEM ONTO NODE
+]
+
+DUMMAK: PUSH TP,A
+ PUSH TP,B
+ PUSH TP,C
+ PUSH TP,D
+ MOVEI A,ASOLNT
+ PUSHJ P,IBLOCK
+ MOVSI A,400000+SASOC+.VECT.
+ MOVEM A,ASOLNT(B) ;SET SPECIAL TYPE
+ MOVEM B,DUMNOD+1
+ POP TP,D
+ POP TP,C
+ POP TP,B
+ POP TP,A
+ POPJ P,
+
+CLOBTB: SETZ ITEM(B)
+ SETZ ITEM+1(B)
+ SETZ INDIC(B)
+ SETZ INDIC+1(B)
+ SETZ VAL(B)
+ SETZ VAL+1(B)
+
+MFUNCTION ASSOCIATIONS,SUBR
+
+ ENTRY 0
+ MOVE B,NODES+1
+ASSOC1: MOVSI A,TASOC ; SET TYPE
+ HRRZ B,NODPNT(B) ; POINT TO 1ST REAL NODE
+ JUMPE B,IFALSE
+ JRST FINIS
+
+; RETURN NEXT ASSOCIATION IN CHAIN OR FALSE
+
+MFUNCTION NEXT,SUBR
+
+ ENTRY 1
+
+ GETYP 0,(AB) ; BETTER BE ASSOC
+ CAIE 0,TASOC
+ JRST WTYP1 ; LOSE
+ MOVE B,1(AB) ; GET ARG
+ JRST ASSOC1
+
+; GET ITEM/INDICATOR/VALUE CELLS
+
+MFUNCTION %ITEM,SUBR,ITEM
+
+ MOVEI B,ITEM ; OFFSET
+ JRST GETIT
+
+MFUNCTION INDICATOR,SUBR
+
+ MOVEI B,INDIC
+ JRST GETIT
+
+MFUNCTION AVALUE,SUBR
+
+ MOVEI B,VAL
+GETIT: ENTRY 1
+ GETYP 0,(AB) ; BETTER BE ASSOC
+ CAIE 0,TASOC
+ JRST WTYP1
+ ADD B,1(AB) ; GET ARG
+ MOVE A,(B)
+ MOVE B,1(B)
+ JRST FINIS
+
+LHCLR: PUSH P,A
+ GETYP A,A
+ PUSHJ P,NWORDT ; DEFERRED ?
+ SOJE A,LHCLR2
+ POP P,A
+LHCLR1: TLZ A,TYPMSK#<-1>
+ POPJ P,
+LHCLR2: POP P,A
+ HLLZS A
+ JRST LHCLR1
+
+END
+\f
\ No newline at end of file