*DECK STRMGR
  PROC BASSMGR; 
  BEGIN 
  
        # STRING MANAGER #
  
        # PROGRAMMED BY J.K.ELLIOTT.   29 JUL 77 #
  
        # STRING MANAGER IS A SET OF FIVE PROCEEDURS THAT 
          MANAGE A DYNAMIC STRING BUFFER. THE ROUTINES ARE
          BASSMGS, BASSMES, BASSMTS, BASSMRS, AND BASSMSQ.
          THE FIRST FOUR ARE FOUND HERE WRITTEN IN SYMPL. 
          BASSMSQ IS WRITTEN IN COMPASS AND IS FOUND IN BASEGEN,
          TOGETHER WITH THE INTERFACE AND MEMORY MAMAGER ROUTINES.
          THE FIRST FOUR OF THESE ARE EXTERNALLY CALLABLE 
          VIA THE COMPASS INTERFACE ROUTINE BASSMIF 
          THRU ENTRY POINTS BASGSTR, BASESTR, BASTSTR, AND
          BASRSTR RESPECTIVLY.  IN ADDITION TO THESE ROUTINES 
          THE COMPASS ROUTINE BASSMMM IS USED TO MANAGE MEMORY. 
  
          EACH OF THE SYMPL PROCS IS INDIVIDUALLY DESCRIBED 
          WITHIN ITS CODE.  BRIEFLY HOWEVER, BASSMGS GETS OR
          ALLOCATES STRING SPACE, BASSMES EXTENDS A STRING
          (ALLOCATES MORE SPACE AT ITS END), BASSMTS TRUNCATES
          A STRING TO A SPECIFIED SIZE, AND BASSMRS RELEASES
          OR DEALLOCATES STRING SPACE.
  
          COMPASS ROUTINE BASSMSQ SQUEEZES OUT
          GARBAGE (DEALLOCATED STRINGS) IN THE STRING AREA.  #
  
                   # EXTERNAL DEFINITIONS # 
  
  XDEF
    BEGIN 
    PROC BASSMGS;        # PROC TO GET OR ALLOCATE STRING # 
    PROC BASSMES;        # PROC TO EXTEND A STRING #
    PROC BASSMTS;        # PROC TO TRUNCATE A STRING #
    PROC BASSMRS;        # PROC TO RETURN OR FREE UP A STRING # 
  
  
    ITEM BASSMFI I=0;     # ADDRESS OF FIRST ITEM IN STRING BUFFER #
    ITEM BASSMLI I=0;     # ADDRESS OF LAST ITEM IN STRING BUFFER # 
    ITEM BASSMLM I=0;     # ADDRESS-1 OF LAST USABLE WORD # 
    ITEM BASSMTG I=0;     # TOTAL NUMBER OF GARBAGE WORDS # 
    ITEM  BASSMGA  I=0;        #INTEGER AVERAGE OF GET LENGTHS# 
    ITEM  BASSMK  I=4;  #K FACTOR USED IN MEMORY REQUEST/RELEASE CALCS# 
                        # W A R N I N G - CHANGE TO BASSMK
                        REQUIRES CHANGE TO BASSMMM CODE#
    END 
  
            # GLOBAL EXTERNAL REFERENCES #
  
  XREF
    BEGIN 
    PROC BASSMMM;   # COMPASS ROUTINE TO MANAGE MEMORY #
    PROC BASSMSQ;  # COMPASS ROUTINE TO SQUEEZE STRING AREA # 
    END 
  
               # GLOBAL DEFS #
  
  DEF CHARSPERWORD # 10 #;    # CHARACTERS PER WORD # 
  DEF GARBTHRESH # O"3000" #; # GARBAGE THRESHOLD # 
  DEF FIRST     # BASSMFI #;  # ADR OF FIRST ITEM IN STRING BUFFER #
  DEF LAST      # BASSMLI #;  # ADR OF LAST ITEM IN STRING BUFFER # 
  DEF LIMIT     # BASSMLM #;  # ADDRESS-1 OF LAST  WORD IS STR BUF #
  DEF MAXLENGTH # 131070 #;   # MAXIMUM STRING LENGTH # 
  DEF MAXWORDS  # 13108 #;    # (MAXLENGHT+ZEROBYTE)/CHARSPERWORD#
  DEF TOTALGARBAGE # BASSMTG #; 
  DEF ZEROBYTE  # 11 #;       # ROUNDING FACTOR # 
  DEF ZERO      # 0 #;
  
             # GLOBAL DATA DECLARATIONS # 
  
  BASED ARRAY STRPOINTER [0:0] S(1); # STRUCTURE OF POINTER WORD #
    BEGIN 
    ITEM TYPECONST B(0,0,1);   # TRUE IF POINTING TO A CONSTANT # 
    ITEM TYPETEMP  B(0,1,1);   # TRUE IF POINTING TO A TEMPORARY #
    ITEM LENGTH    I(0,6,18);  # STR LENGTH (NOT INCLUDING ZERO BYTE) # 
    ITEM EQUPTR    I(0,24,18); # ADDRESS OF EQUATED PTR IF ANY #
    ITEM STRPTR    I(0,42,18); # LOCATION OF STRING DATA #
    ITEM POINTER I(0,0,60);  # POINTER WORD AS A WHOLE #
    END 
  
  BASED ARRAY STRTRAILER [0:0] S(1); # STRUCTURE OF TRAILER WORD #
    BEGIN 
    ITEM GARBLEN   I(0,6,18);  # GARBAGE LENGTH IF STRING IS GARBAGE #
    ITEM NEXTRL    I(0,24,18); # ADDRESS OF NEXT TRAILER #
    ITEM PWADR     I(0,42,18); # ADDRESS OF STRING POINTER WORD # 
    ITEM TRAILER I(0,0,60);  # TRAILER WORD AS A WHOLE #
    END 
  
  CONTROL EJECT;
  PROC BASSMGS(ADDRESS,CHARS);
    BEGIN 
         # STRING MANAGER, GET STRING # 
  
         # THIS ROUTINE RESERVES SPACE FOR THE STRING WHOSE 
         POINTER WORD IS AT LOCATION  "ADDRESS" . 
         IF "CHARS" IS GREATER THAN OR EQUAL TO ZERO, SPACE FOR 
         "CHARS" CHARACTERS PLUS A ZERO BYTE DELIMITER
         IS RESERVED. IF "CHARS" IS LESS THAN ZERO, SPACE FOR AT LEAST
         -"CHARS" CHARACTERS PLUS A ZERO DELIMITER IS RESERVED. 
         ALL SPACE AT THE END OF THE BUFFER IS RESERVED.
         IN BOTH CASES THE STRING POINTED TO BY THE 
         POINTER WORD IS RETURNED BEFORE THE POINTER
         WORD IS UPDATED TO REFLECT THE NEW ALLOCATION, 
         THE FIRST WORD ADDRESS OF THE RESERVED AREA
         IS RETURNED IN "ADDRESS", AND THE NUMBER OF
         CHARACTERS RESERVED (NOT INCLUDING THOSE REQUIRED
         FOR THE ZERO BYTE DELIMITER) IS RETURNED IN
         "CHARS".  IF A REQUEST FOR MORE THAN THE MAXIMUM 
         ALLOWED STRING LENGTH IS MADE,  A STRING EQUAL 
         TO THE MAXIMUM IS ALLOCATED.       # 
  
                 # FORMAL PARAMETERS #
  
    ITEM ADDRESS I;       # INPUT = ADDRESS OF STRING POINTER # 
                          # OUTPUT = FWA OF RESERVED SPACE #
    ITEM CHARS I;         # INPUT= NUMBER OF CHARACTERS REQUIRED #
                          # OUTPUT = NUMBER OF CHARACTERS RESERVED #
  
  
  
                 # LOCAL DATA DECLARATIONS #
  
    ITEM AVAILABLE I;     #AVAILABLE WORDS BETWEEN LAST AND LIMIT # 
    ITEM REQUIRED I;      # TOTAL REQUIRED WORDS (INCLUDING ZERO #
                            # BYTE DELIMITER ) #
    ITEM OLDLAST I;       # TEMPORARY ADDRESS OF ORIGINAL TRAILER # 
    ITEM  REALAVGE  R=5.0;  #AVERAGE OF GET LENGTHS AS A REAL QUANTITY# 
    ITEM  NUMOFGETS  I=6;      #NUMBER OF GET REQUESTS IN GET AVGE# 
  
               # BEGIN CODE # 
  
         # RETURN OLD STRING IF NECESSARY # 
  
    P<STRPOINTER> = ADDRESS; # BASE ARRAY ON POINTER WORD # 
    IF POINTER NQ ZERO THEN BASSMRS(ADDRESS); # RETURN OLD STRING # 
  
         # CALCULATE AVAILABLE AND REQUIRED SPACE # 
  
    AVAILABLE = LIMIT-LAST; 
    IF CHARS GR MAXLENGTH OR -CHARS GR MAXLENGTH THEN 
      CHARS = MAXLENGTH;
    IF CHARS GQ ZERO THEN REQUIRED = (CHARS+ZEROBYTE)/CHARSPERWORD; 
    ELSE REQUIRED = (-CHARS+ZEROBYTE)/CHARSPERWORD+1; 
  
              #CALCULATE MOVING AVERAGE OF GET LENGTHS# 
  
              # THE OBJECTIVE HERE IS TO RECALCULATE, EACH
              TIME BASSMGS IS ENTERED, AN AVERAGE OF THE
              LENGTHS (IN WORDS) REQUESTED BY THE LAST
              -X- GET REQUESTS, WHERE -X- IS A CONSTANT = 
              THE ITEM NUMOFGETS. THE CALCULATION YIELDS A
              REAL NUMBER WHICH IS TRUNCATED TO AN INTEGER
              AND STORED IN THE CELL BASSMGA.  BASSMGA
              IS USED BY OTHER ROUTINES AS A FACTOR IN
              THE ACQUISITION/RELEASE OF MEMORY FOR THE STRING
              AREA. 
  
               NOTE THAT THE AVERAGE CALCULATION ROUTINE
            USES A PRE-INITIALIIZED VALUE IN THE CELL REALAVGE. 
            THE INFLUENCE OF THIS PRESET VALUE DIMINISHES AS
            NUMBER OF GET REQUESTS INCREASE.# 
  
    REALAVGE = ((NUMOFGETS-1)*REALAVGE+REQUIRED)/NUMOFGETS; 
    BASSMGA = REALAVGE;     #SETUP INTEGER AVERAGE OF GETS# 
  
  
  
  
  
  
         # SQUEEZE OUT GARBAGE AND GET MORE MEMORY #
        # IF AVAILABLE SPACE LESS THAN REQUIRED SPACE # 
  
    IF REQUIRED GR AVAILABLE THEN 
      BEGIN 
      BASSMSQ;         # GO SQUEEZE OUT GARBAGE AND PACKUP STRINGS #
      AVAILABLE = LIMIT-LAST; # NOTE- LAST IS UPDATED BY BASSMSQ #
      IF REQUIRED GR AVAILABLE THEN 
        BEGIN 
        BASSMMM (REQUIRED-AVAILABLE); # GET MORE MEMORY # 
        AVAILABLE = LIMIT-LAST; # NOTE-LIMIT IS UPDATED BY BASSMMM #
        END 
      END 
  
         # ALLOCATE THE REQUIRED SPACE #
  
    IF CHARS LS ZERO THEN 
      BEGIN 
      IF AVAILABLE LS MAXWORDS THEN 
        REQUIRED = AVAILABLE;   # ALLOCATE ALL THAT IS AVAILABLE #
      ELSE
        REQUIRED = MAXWORDS;    # ALLOCATE ONLY MAXIMUM STRING #
      END 
    OLDLAST=LAST;        # SAVE ADDRESS OF ORIGINAL LAST TRAILER #
    P<STRTRAILER> = OLDLAST; # BASE ARRAG ON ORIGINAL LAST TRAILER #
    LAST = LAST + REQUIRED+1; # POINT LAST TO NEW LAST TRAILER #
    IF FIRST EQ ZERO THEN 
      BEGIN               # THIS IS FIRST STRING ALLOCATED. CREATE AN # 
      PWADR = -1;        # ARTIFICIAL, ZERO LENGTH, GARBAGE TRAILER # 
      GARBLEN = ZERO;    # WORD AT BEGINNING OF STRING BUFFER SO #
      NEXTRL = LAST;      # OTHER OPERATIONS WILL ALWAYS FIND A # 
      FIRST = OLDLAST;    # PREVIOUS TRAILER #
      END 
    ELSE    # THIS IS NOT FIRST STRING ALLOCATED #
      BEGIN 
      NEXTRL = LAST;       # UPDATE POINTER TO NEXT TRAILER # 
      END 
    P<STRTRAILER> = LAST;  # BASE ARRAY ON NEW LAST TRAILER # 
    NEXTRL = ZERO;        # MARK IT AS LAST TRAILER # 
    PWADR = ADDRESS;      # SET POINTER TO STRING POINTER WORD #
  
         # UPDATE THE STRING POINTER WORD # 
  
    P<STRPOINTER>=ADDRESS;  # RESET BASE, OTHER PROCS MOVE IT # 
    TYPETEMP = TRUE;
    IF CHARS GQ ZERO THEN LENGTH = CHARS; 
    ELSE LENGTH = (REQUIRED-1)*CHARSPERWORD;
    STRPTR = OLDLAST+1; 
  
         #UPDATE RETURN PARAMETERS AND RETURN # 
  
    CHARS = LENGTH; 
    ADDRESS = OLDLAST+1; # STRING STARTS 1 WORD AFTER OLD TRAILER # 
    RETURN; 
    END 
  CONTROL EJECT;
  PROC BASSMES (ADDRESS,CHARS); 
    BEGIN 
  
       # STRING MANAGER, EXTEND STRING #
  
       # THIS ROUTINE EXTENDS THE STRING WHOSE POINTER
         WORD IS AT LOCATION  "ADDRESS"  BY  "CHARS"  CHARACTERS
         IF  "CHARS"  IS GREATER THAN ZERO OR BY AT LEAST 
         - "CHARS"  CHARACTERS IF  "CHARS"  IS LESS THAN ZERO.
         IN BOTH CASES SPACE FOR A ZERO BYTE DELIMITER IS 
         GARENTEED. THE STRING POINTER WORD IS
         UPDATED TO REFLECT THE NEW LENGTH AND NEW FWA, 
         TRAILER WORDS ARE UPDATED, AND PARAMETERS
         "ADDRESS"  AND  "CHARS"  ARE SET TO THE NEW FWA
         (THE STRING MAY BE MOVED AS A RESULT OF SQUEEZING
         OUT GARBGARBAGE) AND THE NEW LENGTH (NOT INCLUDING 
         THE ZERO BYTE DELIMITER) RESPECTIVLY.
         THE STRING TO BE EXTENDED MUST BE THE LAST STRING
         IN THE BUFFER. IF IT IS NOT THE EXISTING FWA 
         AND LENGTH ARE RETURNED I.E. THE STRING IS NOT 
         EXTEENDED.   ALSO, A STRING CAN NEVER BE EXTENDED
         BEYOND MAXIMUM LENGTH.     # 
  
  
                 # FORMAL PARAMETERS #
  
    ITEM ADDRESS I;   # INPUT = ADDRESS OF STRING POINTER WORD #
                      # OUTPUT = ADDRESS OF FIRST WORD OF STRING #
  
    ITEM CHARS I;     # INPUT = NUMBER OF ADDITIONAL CHARS DESIRED #
                      # OUTPUT = TOTAL NUMBER OF CHARS IN THE STRING #
  
                 # LOCAL DATA DECLARATIONS #
  
    ITEM LOCALSPW I=0; # TEMPORAY STRING POINTER WORD # 
    ITEM ZEROCHARS I;  # CHARS IN STRING'S ZERORYTE DELIMITER # 
    ITEM NEWCHARS I;   # NEW CHARACTERS WANTED/GRANTED #
    ITEM NEWLENGTH I;  # LENGTH OF EXTENDED STRING #
  
                # BEGIN CODE #
  
      # ENSURE STRING IS EXTENDABLE. IT MUST BE LAST IN BUFFER #
  
    P<STRPOINTER> = ADDRESS;
    P<STRTRAILER> = LAST;      # BASE ARRAY OVER LAST TRAILER # 
    IF TYPETEMP AND PWADR EQ ADDRESS THEN 
      BEGIN 
  
         # INITIALIZE  #
  
      LOCALSPW = ZERO;  # CLEAR LOCAL STRING POINTER WORD # 
      P<STRPOINTER> = ADDRESS;  # BASE ARRAY OVER STRING POINTER WORD # 
      ZEROCHARS = (LAST-STRPTR) *10 - LENGTH ; # NUMBER OF ZERO BYTES # 
      NEWCHARS = CHARS; 
  
  
          # EXTEND BY INDEFINITE AMOUNT # 
  
      IF NEWCHARS LS ZERO THEN
        BEGIN 
        BASSMGS (LOC(LOCALSPW),NEWCHARS);   # GET A NEW STRING #
        NEWCHARS = NEWCHARS+10; # ADJUST FOR REUSE OF ORIGINAL TRAILER #
        END 
  
          # EXTEND BY A DEFINITE AMOUNT # 
  
      ELSE      # NEWCHARS GQ ZERO #
        BEGIN 
        NEWCHARS = NEWCHARS - ZEROCHARS;  # REUSE OF OLD ZERO BYTES#
        IF NEWCHARS GR -2 THEN
          BEGIN               # EXTENSION WON'T FIT WITHIN ZERO BYTE #
          IF NEWCHARS LQ ZERO THEN    # GET A NEW STRING #
            BEGIN                     # ENSURE REQUEST IS FOR A # 
            NEWCHARS = NEWCHARS + 2; # POSITIVE NUMBER OF CHARS # 
            ZEROCHARS = ZEROCHARS-2;
            END 
          BASSMGS (LOC(LOCALSPW),NEWCHARS); # GO GET NEW STRING # 
          LAST = LAST-1; # ADJUST LAST TO ACCOUNT FOR REUSE # 
          END            # OF OLD TRAILER # 
        END 
  
          # UPDATE STRING POINTER WORD #
  
      P<STRPOINTER>=ADDRESS;  # RESET BASE. BASSMGS MOVED IT #
      NEWLENGTH = LENGTH+NEWCHARS+ZEROCHARS; #LENGTH OF EXTENDED STR# 
      IF NEWLENGTH GR MAXLENGTH THEN
        BEGIN 
        LENGTH = MAXLENGTH; 
        LAST = STRPTR+(MAXLENGTH+ZEROBYTE)/CHARSPERWORD;
        END 
      ELSE
        LENGTH = NEWLENGTH; 
  
           # ADJUST TRAILER PRECEEDING ORIGINAL STRING #
        # TO POINT TO NEW LAST TRAILER #
  
      P<STRTRAILER> = STRPTR -1 ;  # PRECEEDING TRAILER IS I WORD # 
      NEXTRL = LAST;               # BEFORE FWA OF ORIGINAL STR # 
  
           # CREATE NEW LAST TRAILER WORD # 
  
      P<STRTRAILER> = LAST;  # BASE ARRAY ON NEW TRAILER #
      NEXTRL= ZERO; 
      PWADR = ADDRESS;
      END 
  
         # SET UP RETURN VALUES AND RETURN #
  
    CHARS = LENGTH; 
    ADDRESS = STRPTR; # ORIGINAL FWA MAY HAVE BEEN MOVED #
    RETURN; 
    END 
  CONTROL EJECT;
  PROC BASSMTS (ADDRESS,CHARS); 
    BEGIN 
  
                # STRING MANAGER, TRUNCATE STRING # 
  
       # THIS ROUTINE TRUNCATES THE STRING WHOSE POINTER
         IS AT LOCATION "ADDRESS" TO "CHARS" CHARACTERS.
         THE STRING IS ASSUMED TO BE A TEMPORAY STRING
         AT THE END OF THE STRING BUFFER.  IF IT IS NOT 
         NO ACTION IS TAKEN.  THE FREED UP
         CHARACTERS, THE WORDS TRUNCATED OFF THE END, ARE 
         ABSORBED BACK INTO THE AVAILABLE SPACE 
         AT THE END OF THE STRING BUFFER.  SPACE IS RESERVED
         FOR A ZERO BYTE DELIMITER BUT ONE IS NOT EXPLICITLY CREATED
         BY THIS ROUTINE.  THE CALLING PROGRAM MUST ENSURE A ZERO 
         BYTE DELIMITER IS STORED AFTER "CHARS" CHARACTERS.  A ZERO 
         OR NEGATIVE VALUE OF "CHARS" CAUSES THE ENTIRE 
         STRING TO BE FREED AND THE POINTER WORD AT "ADDRESS" TO
         BE CLEARED TO ZERO.  ON EXIT, TRAILER AND POINTER WORDS
         ARE UPDATED, "ADDRESS" IS SET TO THE FWA OF THE STRING,
         AND "CHARS" IS SET TO THE NUMBER OF CHARACTERS 
         IN THE TRUNCATED STRING. # 
  
  
                 # FORMAL PARAMETERS #
  
    ITEM ADDRESS I;   # INPUT=ADDRESS OF STRING POINTER WORD #
                      # OUTPUT=ADDRESS OF FIRST WORD OF STRING #
  
    ITEM CHARS I;     # INPUT=DESIRED NEW LENGTH OF STRING #
                      # OUTPUT=NEW LENGTH OF STRING # 
  
            # LOCAL DATA DEFINITIONS #
  
    ITEM TEMPLAST I;  # ADDRESS OF TEMPORARY LAST WORD #
  
             # BEGIN CODE # 
  
       # ENSURE STRING IS LAST AND ITS A TEMPORARY #
  
    P<STRPOINTER>=ADDRESS;  # BASE ARRAY ON STRING POINTER #
    P<STRTRAILER>=LAST;     # BASE ARRAY ON LAST TRAILER WORD # 
    IF PWADR EQ ADDRESS AND TYPETEMP THEN 
      BEGIN 
  
              # INITIALIZE #
  
      TEMPLAST=STRPTR-1;   # ADDRESS OF NEXT TO LAST TRAILER #
      P<STRTRAILER>=TEMPLAST; # BASE ARRAY ON NEXT TO LAST TRL WORD # 
  
              # TRUNCATE TO ZERO LENGTH # 
  
      IF CHARS LQ ZERO THEN 
        BEGIN 
        LAST=TEMPLAST;  # MAKE NEXT TO LAST TRL LAST TRAILER #
        POINTER=ZERO;  # ZERO ENTIRE POINTER WORD # 
        NEXTRL=ZERO;  # MARK TRAILER AS LAST TRAILER #
        CHARS=ZERO;  # ENSURE RETURN VALUE IS ZERO #
        END 
  
              # TRUNCATE TO NON ZERO LENGTH # 
  
      ELSE       # CHARS GR ZERO #
        BEGIN 
        LAST=(CHARS+ZEROBYTE)/10+1+TEMPLAST;  # NEW LAST ADDRESS #
        NEXTRL=LAST; # UPDATE TRAILER TO POINT TO NEW LAST TRL #
        P<STRTRAILER>=LAST;  # BASE ARRAY ON NEW LAST TRAILER # 
        NEXTRL=ZERO;  # UPDATE NEW LAST TRAILER # 
        PWADR=ADDRESS;
        END 
  
             # UPDATE STRING POINTER WORD # 
  
      LENGTH = CHARS; 
  
              # SET UP RETURN VALUES AND RETURN # 
  
      ADDRESS=STRPTR;  # RETURN FWA OF STRING - ZERO IF NONE #
      END 
    RETURN; 
    END 
  CONTROL EJECT;
  PROC BASSMRS (ADDRESS); 
    BEGIN 
  
         # STRING MANAGER, RELEASE STRING # 
  
         # THIS ROUTINE RELEASES OR FREES UP THE STRING 
         WHOSE POINTER WORD IS AT LOCATION "ADDRESS". 
         IF THE POINTER WORD IS ZERO OR POINTS TO A 
         CONSTANT, IT IS SIMPLY CLEARED TO ZERO.  IF
         IT POINTS TO AN ACTIVE STRING VARIABLE, IT IS
         BROKEN OUT OF THE EQUATE CHAIN IF IT IS EQUATED
         TO OTHER POINTER WORDS THAT POINT TO THE SAME
         STRING, OTHERWISE THE TRAILER OF THE STRING
         IT POINTS TO IS MARKED TO INDICATE THAT THE
         STRING IS GARBAGE IF IT ISN'T EQUATED.  IN EITHER
         CASE THE POINTER WORD IS CLEARED TO ZERO.
  
         WHEN THE TOTAL AMOUNT OF GARBAGE 
         EXCEEDS "GARBTHRESH", THE MEMORY MANAGER 
         ROUTINE IS CALLED TO RETURN MEMORY TO THE
         SYSTEM                                         # 
  
  
               # FORMAL PARAMETERS #
  
    ITEM ADDRESS I; # INPUT = ADDRESS OF STRING POINTER WORD #
                    # OUTPUT = SAME # 
  
               # LOCAL DATA DECLARATIONS #
  
    ITEM FOUND B;     # BOOLEAN TO CONTROL FOR LOOP # 
    ITEM I   I;       # FOR LOOP INDEX #
    ITEM TOPOINTER I; # ADDRESS OF EQUATED POINTER WORD # 
    ITEM FMPOINTER I; # ADDRESS OF PTR THAT POINTS TO THIS ONE #
    ITEM PCENT  R=.5; #FACTOR USED IN DETERMINING IF SQUEEZE REQD#
    ITEM MEMDOWN I=0; #TEMPORARY# 
  
           # BEGIN CODE # 
  
          # ENSURE POINTER WORD IS ACTIVE # 
  
    P<STRPOINTER> = ADDRESS; # BASE ARRAY ON POINTER WORD # 
    IF NOT TYPECONST AND POINTER NQ ZERO THEN 
      BEGIN                 # POINTER IS VALID #
      P<STRTRAILER> = STRPTR+(LENGTH+ZEROBYTE)/CHARSPERWORD;
  
       # RELEASE EQUATED POINTER - BREAK OUT OF EQUATE CHAIN #
  
      IF EQUPTR NQ ZERO THEN
        BEGIN 
        PWADR = EQUPTR; # POINT TRAILER TO RETAINED POINTER WRD#
        TOPOINTER = EQUPTR; # SAVE ADDRESS POINTED TO # 
        FOUND = FALSE;
        FOR I = TOPOINTER WHILE NOT FOUND DO
          BEGIN    # FIND STRING POINTER WORD THAT POINTS # 
                             # TO THE ONE BEING RELEASED# 
          P<STRPOINTER> = I;
          FMPOINTER = I;
          IF EQUPTR EQ ADDRESS THEN FOUND = TRUE; 
          ELSE I = EQUPTR;
          END 
  
        IF FMPOINTER EQ TOPOINTER THEN
          BEGIN  # THIS IS 2 LINK CHAIN CLEAR EQUPTR IN # 
          EQUPTR=ZERO;  # POINTER WORD THAT POINTS TO ONE # 
          END           # BEING RELEASED #
        ELSE
          BEGIN         # THIS IS MULTILINK CHAIN. SET EQUPTR IN WORD # 
          EQUPTR=TOPOINTER; # THAT POINTS TO ONE BEING RELEASE TO # 
          END               # THE ADDRESS OF THE WORD POINTED TO BY # 
                           # THE ONE BEING RELEASED # 
        END 
  
  
         # RELEASE NON EQUATED STRING - MARK STRING AS GARBAGE. # 
  
  
      ELSE # EQUPTR EQ ZERO # 
        BEGIN 
        PWADR=-1; # MARK TRAILER AS GARBAGE TRAILER # 
        GARBLEN=(LENGTH+ZEROBYTE)/CHARSPERWORD+1; # GARBAGE WORDS # 
        TOTALGARBAGE=TOTALGARBAGE+GARBLEN;
  
           # RELEASE MEMORY IF TOO MUCH GARBAGE # 
  
    IF TOTALGARBAGE GR (GARBTHRESH + BASSMK * BASSMGA)
      THEN
      BEGIN 
      IF TOTALGARBAGE GR PCENT*(LIMIT-FIRST)
        THEN
        BEGIN 
        MEMDOWN = TOTALGARBAGE - (BASSMK * BASSMGA); #AMT TO DROP MEM#
        BASSMSQ;    #SQUEEZE OUT ALL GARBAGE #
        BASSMMM (-MEMDOWN);    # GO RETURN EXCESS OF MEMORY#
        END 
     END
   END
 END
  
     # CLEAR RELEASED STRING POINTER WORD AND RETURN #
  
    P<STRPOINTER> = ADDRESS;  # BASE ARRAY ON ORIGINAL POINTER# 
    POINTER=ZERO; 
    RETURN; 
  END 
  
  END 
  TERM
