NEW
  AUTO 3,1
*--------------------------------------
*      INITIALIZE SYMBOL TABLE
*      1.  SET EOT TO BOT
*      2.  CLEAR HASH POINTER TABLE
*--------------------------------
STINIT LDA LO.MEM    START OF SYMBOL TABLE
       STA EOT
       LDA LO.MEM+1
       STA EOT+1
       STA MACLBL+1 PRIVATE LABELS GO DOWN FROM THERE
       LDX #56      # BYTES IN HASH POINTER TABLE
       LDA #0
       STA MACLBL
       STA CURRENT.MAJOR.LABEL+1
.1     STA HSHTBL-1,X
       DEX
       BNE .1
  .DO AUXMEM
       LDA RDRAM
       LDA RDRAM
       LDX #AUX.IMAGE.LEN-1
.2     LDA AUX.IMAGE,X
       STA AUX.CODE,X
       DEX
       BPL .2
BACK.TO.ROM
       PHA
       LDA RDROM
       PLA
  .FIN
       RTS          RETURN WITH X=0
*--------------------------------
   .DO AUXMEM
LDA.STPNTR
       BIT RDRAM
       JSR LDA.STPNTR.AUX
       JMP BACK.TO.ROM
*
ADC.STPNTR
       BIT RDRAM
       JSR ADC.STPNTR.AUX
       JMP BACK.TO.ROM
*
SBC.STPNTR
       BIT RDRAM
       JSR SBC.STPNTR.AUX
       JMP BACK.TO.ROM
*
LDA.PNTR
       BIT RDRAM
       JSR LDA.PNTR.AUX
       JMP BACK.TO.ROM
*
LDA.TPTR
       BIT RDRAM
       JSR LDA.TPTR.AUX
       JMP BACK.TO.ROM
*
LDA.SRCP
       BIT RDRAM
       JSR LDA.SRCP.AUX
       JMP BACK.TO.ROM
*
STA.PNTR
       STA WRAUX
       STA (PNTR),Y
       STA WRMAIN
       RTS
STA.STPNTR
       STA WRAUX
       STA (STPNTR),Y
       STA WRMAIN
       RTS
*--------------------------------
AUX.IMAGE
LDA.STPNTR.AUX .EQ *-AUX.IMAGE+AUX.CODE
       STA RDAUX
       LDA (STPNTR),Y
       STA RDMAIN
       RTS
ADC.STPNTR.AUX .EQ *-AUX.IMAGE+AUX.CODE
       STA RDAUX
       ADC (STPNTR),Y
       STA RDMAIN
       RTS
SBC.STPNTR.AUX .EQ *-AUX.IMAGE+AUX.CODE
       STA RDAUX
       SBC (STPNTR),Y
       STA RDMAIN
       RTS
LDA.PNTR.AUX .EQ *-AUX.IMAGE+AUX.CODE
       STA RDAUX
       LDA (PNTR),Y
       STA RDMAIN
       RTS
LDA.TPTR.AUX .EQ *-AUX.IMAGE+AUX.CODE
       STA RDAUX
       LDA (TPTR),Y
       STA RDMAIN
       RTS
LDA.SRCP.AUX .EQ *-AUX.IMAGE+AUX.CODE
       STA RDAUX
       LDA (SRCP),Y
       STA RDMAIN
       RTS
AUX.IMAGE.LEN .EQ *-AUX.IMAGE
   .FIN
*--------------------------------
*      A table of 28 pointers begins at $130, called HSHTBL.
*      Each pointer points to the beginning of a chain of
*      symbol entries.  The entries on a chain are kept
*      in alphabetical order.  If a chain is empty, the
*      pointer = $0000.
*
*      HSHTBL+$00:  Chain for target file entries
*      HSHTBL+$02:  Chain for labels starting with "A"
*      HSHTBL+$04:  Chain for labels starting with "B"
*        - - -
*      HSHTBL+$34:  Chain for labels starting with "Z"
*      HSHTBL+$36:  Chain for Macro Names and Skeletons
*
*      Format of Target File Entry:
*          0,1 -- Forward chain pointer (0=end of chain)
*          2,3 -- Length of target file in bytes
*          4   -- Length of code name = $02
*          5,6 -- Target file code name:
*                 5:  "@" = $40
*                 6:  $40 + target file number ($00-$1F)
*
*      Format of Label Entry:
*          0,1 -- Forward chain pointer (0=end of chain)
*          2-5 -- Value of label
*          6   -- Flags and length of label name:
*                 Bits 5-0:  length of label name ($01-$20)
*                 Bit    6:  =1 if forward reference
*                 Bit    7:  =1 if has local labels
*          7   -- First character of label name, and flag.
*                 Bit 7 = 1 if label is .SEt label.
*     thru 6+n -- The rest of the label name, with bit 7 = 0
*
*          If the label has local labels, they follow.
*          Each local label occupies two bytes:
*          1   -- Label number (0-99) +128
*          2   -- Label value (distance from value of
*                   named label)
*          The local label list is terminated with a $00
*                   in the label number position.
*
*      Format of Macro Definition Entry:
*          0,1 -- Chain to next macro name
*          2,3 -- $0000
*          4   -- Length of macro name
*          5   -- "[" + $5B
*          6-n -- Rest of Macro name
*          etc.-- The packed skeleton lines, each
*                   terminated by $00.  A final $00
*                   terminates the skeleton.
*
*      Private Labels are kept in a separate table.
*      Each label takes 7 bytes.  Bytes 0-3 are the
*      value, byte 4 is the colon number + $80,
*      and bytes 5 and 6 are the macro call number.
*      The Private Label table grows downward from
*      MACLBL toward $0800.
*
*--------------------------------
*      PACK SYMBOL FROM INPUT LINE
*      UP TO 32 CHARACTERS PACKED AT SYMBOL+7
*      AND FOLLOWING.
*      # CHARS STORED IN SYMBOL+6
*      RETURN CARRY CLEAR IF NO SYMBOL
*      RETURN CARRY SET IF GOOD SYMBOL
*--------------------------------
PACK   LDX #0       POINT AT 1ST CHAR IN NAME
       CMP #CHR.PERIOD LOCAL SYMBOL?
       BEQ .1       YES
       CMP #':      COLON MEANS MACRO PRIVATE LABEL
       BNE .3       NO, NORMAL SYMBOL
.1     STA SYMBOL+7 SAVE PERIOD OR COLON
       JSR GNC.UC   GET NEXT CHAR
       JSR CHECK.DIGIT
       BCC .4       NO, BAD SYMBOL
       JSR DECN     CONVERT TO BINARY
       LDX #0       IN CASE BAD SYMBOL...
       LDA DGTCNT         VALUE MUST BE < 100
       CMP #3            SO MUST BE 1 OR 2 DIGITS
       BCS .4       ...TOO MANY DIGITS, BAD SYMBOL
       LDA SYM.VALUE
       ORA #$80     BE SURE NOT 00
       STA SYMBOL+8 SAVE VALUE
       LDA CALL.NUM JUST IN CASE IT'S A
       STA SYMBOL+9 MACRO PRIVATE LABEL
       LDA CALL.NUM+1
       STA SYMBOL+10
       INX          SIGNAL GOOD SYMBOL
       BNE .4       ...ALWAYS
*--------------------------------
.3     JSR PACK.NAME
.4     JSR BACKUP.CHAR.PNTR
       STX SYMBOL+6 SAVE LENGTH
       CPX #1       CARRY SET IF AT LEAST ONE CHAR
       LDX #0       CLEAR X AGAIN
       RTS
*--------------------------------
*      PACK A NAME INTO SYMBOL
*--------------------------------
PACK.NAME
       JSR CHECK.LETTER
       BCC .4       NOT A LETTER
.1     CPX #32      SEE IF ALREADY 32 CHARACTERS
       BEQ .2       YES, IGNORE
       STA SYMBOL+7,X PUT CHAR IN ENTRY
       INX          POINT AT NEXT SLOT
.2     JSR GNC.UC   GET NEXT CHAR FROM LINE
       JSR CHECK.DOT.DIGIT.OR.LETTER
       BCS .1       VALID CHAR
.4     RTS          END OF NAME
*--------------------------------
*      SEARCH SYMBOL TABLE
*      # OF CHARS STORED AT SYMBOL+6
*      SYMBOL ITSELF AT SYMBOL+7 AND FOLLOWING
*      JSR STSRCH
*      IF FOUND: CARRY CLEAR
*                (STPNTR)=ADDRESS OF ENTRY
*      IF NOT FOUND: CARRY SET
*                    (STPNTR)=ADDRESS OF
*                    POINTER CELL WHICH
*                    SHOULD POINT AT ENTRY
*--------------------------------
STSRCH SEC          CONVERT FIRST CHARACTER
       LDA SYMBOL+7 OF SYMBOL TO HASH TABLE INDEX
       CMP #CHR.PERIOD SEE IF LOCAL SYMBOL
       BEQ .8       YES
       CMP #':      COLON, THEN PRIVATE LABEL
       BNE .12      NO, NORMAL LABEL
       JMP SEARCH.PRIVATE.LABELS
.12    SBC #$40     AT-SIGN
       ASL          DOUBLE INDEX, CLEAR CARRY
       ADC #HSHTBL
       STA STPNTR
       LDA /HSHTBL
       ADC #0
       STA STPNTR+1
.1     LDY #0
       >SYM LDA,STPNTR GET POINTER FROM ENTRY
       STA TPTR
       INY
       >SYM LDA,STPNTR
       BEQ .4       END OF CHAIN, NOT IN TABLE
       STA TPTR+1
       LDX SYMBOL+6 # CHARS IN SYMBOL
       LDY #6       POINT AT LENGTH
       >SYM LDA,TPTR USE MINIMUM LENGTH
       AND #$3F     ISOLATE LENGTH
       CMP SYMBOL,Y
       INY
       BCS .2
       TAX
.2     >SYM LDA,TPTR COMPARE BYTES FROM BOTH
       AND #$7F     ALLOW FLAG BITS IN SYMBOL
       CMP SYMBOL,Y
       BCC .3       NOT THIS ONE, BUT KEEP LOOKING
       BNE .4       NOT IN THIS CHAIN
       DEX
       BEQ .5       THE NAME IS THE SAME OR A SUBSET
       INY          NEXT BYTE PAIR
       BNE .2       ...ALWAYS
.3     JSR .7       UPDATE POINTER, CLEAR CARRY
       BCC .1       ...ALWAYS
.4     SEC          DID NOT FIND
       LDX #0       RESTORE X=0
       RTS
.5     LDY #6       TEST LENGTHS
       >SYM LDA,TPTR
       AND #$3F     ISOLATE LENGTH
       CMP SYMBOL+6 # CHARS IN SYMBOL IN TABLE
       BEQ .6       SAME EXACTLY
       BCS .4       NEW SYMBOL IS SHORTER
       BCC .3       NEW SYMBOL IS LONGER
.6     LDY #2       POINT AT VALUE
.65    >SYM LDA,TPTR SET UP VALUE FOR EXPR SCAN
       STA SYM.VALUE-2,Y
       INY
       CPY #6
       BCC .65
.7     LDA TPTR
       STA STPNTR
       LDA TPTR+1
       STA STPNTR+1
       CLC          SIGNAL DID FIND IT
       RTS
*--------------------------------
.8     LDA CURRENT.MAJOR.LABEL
       STA STPNTR
       LDA CURRENT.MAJOR.LABEL+1
       BEQ .11
       STA STPNTR+1
       CLC
       LDY #6       POINT AT LENGTH
       >SYM LDA,STPNTR GET LENGTH OF MAJOR SYMBOL
       BPL .4       NO LOCAL SYMBOLS YET
       AND #$3F     MASK TO REAL LENGTH
       ADC #7       POINT AT LOCALS
       TAY
.9     >SYM LDA,STPNTR
       BEQ .4       END OF LOCALS, NOT FOUND
       CMP SYMBOL+8 COMPARE TO NAME OF LOCAL
       BEQ .10      FOUND IT!
       INY          SKIP TO NEXT LOCAL
       INY
       BNE .9       ...ALWAYS
.10    INY          POINT AT VALUE OFFSET
       >SYM LDA,STPNTR
       CLC
       LDY #2       POINT AT MAJOR VALUE
       >SYM ADC,STPNTR
       STA SYM.VALUE
       INY
       >SYM LDA,STPNTR
       ADC #0
       STA SYM.VALUE+1
       INY
       >SYM LDA,STPNTR
       ADC #0
       STA SYM.VALUE+2
       INY
       >SYM LDA,STPNTR
       ADC #0
       STA SYM.VALUE+3
       CLC
       RTS
.11    LDY #QER9     NO NORMAL LABEL YET
       JMP SOFT.ERROR
*--------------------------------
*      SEARCH PRIVATE LABEL TABLE
*--------------------------------
SEARCH.PRIVATE.LABELS
       LDA MACLBL
       STA STPNTR
       LDA MACLBL+1
.1     STA STPNTR+1
       CMP LO.MEM+1       END OF TABLE YET?
       BCS .3            ...YES, NO MORE LABELS
       LDY #6
       >SYM LDA,STPNTR
       AND #$3F     ISOLATE FROM FLAG BITS
       CMP SYMBOL+10
       BNE .2       NO
       DEY
       >SYM LDA,STPNTR
       CMP SYMBOL+9
       BNE .2       NO
       DEY
       >SYM LDA,STPNTR
       CMP SYMBOL+8
       BEQ .4       YES, FOUND IT!
.2     CLC          BUMP PNTR TO NEXT LABEL
       LDA STPNTR
       ADC #7
       STA STPNTR
       LDA STPNTR+1
       ADC #0
       BNE .1       ...ALWAYS
*--------------------------------
.3     SEC          SIGNAL NOT FOUND
       RTS
*--------------------------------
.4     DEY
.5     >SYM LDA,STPNTR
       STA SYM.VALUE,Y
       DEY
       BPL .5
       CLC
       RTS
*--------------------------------
*      ADD SYMBOL TO TABLE
*--------------------------------
STADD  LDA SYMBOL+7 SEE IF LOCAL SYMBOL
       CMP #CHR.PERIOD
       BEQ .5       YES
       CMP #':      COLON, PRIVATE LABEL
       BNE .11      NO, NORMAL LABEL
       JMP ADD.PRIVATE.LABEL
.11    LDY #1       POINT AT POINTER
.1     >SYM LDA,STPNTR GET CURRENT POINTER
       STA SYMBOL,Y
       LDA EOT,Y
       >SYM STA,STPNTR
       STA PNTR,Y
       STA CURRENT.MAJOR.LABEL,Y
       LDA ORGN,Y   VALUE
       STA SYMBOL+2,Y
       LDA ORGN+2,Y
       STA SYMBOL+4,Y
       DEY
       BPL .1
       CLC          COMPUTE ENTRY SIZE
       LDA SYMBOL+6 FROM SYMBOL SIZE
       ADC #7
.2     PHA          SAVE SIZE
       LDY EOT+1
       CLC
       ADC EOT      SEE IF ROOM FOR NEW ENTRY
       BCC .10
       INY
  .DO AUXMEM
.10    CPY /$C000
       BCS .4       MEM FULL ERR
       STA EOT
  .ELSE
.10    CMP MACSTK
       TAX          SAVE LOW BYTE
       TYA          GET HIGH BYTE
       SBC MACSTK+1
       BCS .4       MEM FULL ERR
       STX EOT
  .FIN
       STY EOT+1
       PLA          GET SIZE
       TAY
       DEY          CORRECT FOR INDEXING
.3     LDA SYMBOL,Y
       >SYM STA,PNTR
       DEY
       BPL .3
       RTS
.4     JMP MFER     MEM FULL ERR
*--------------------------------
.5     LDY #6       LENGTH BYTE
       >SYM LDA,STPNTR
       BMI .6       ALREADY HAVE SOME LOCAL LABELS
       ORA #$80     SET LOCAL FLAG
       >SYM STA,STPNTR
       BNE .8       ...ALWAYS
.6     LDA EOT      BACK UP EOT
       BNE .7       OVER 00 TERMINATOR
       DEC EOT+1    OF LOCALS
.7     DEC EOT
.8     LDA SYMBOL+8 NAME OF LOCAL
       STA SYMBOL   SET UP TO ADD TO SYMBOL TABLE
       SEC
       LDY #1
       JSR CALC.OFFSET.BYTE
       JSR CALC.OFFSET.BYTE
       BNE .9       ERROR > 255
       JSR CALC.OFFSET.BYTE
       BNE .9       ERROR > 255
       JSR CALC.OFFSET.BYTE
       BNE .9       ERROR > 255
       LDA EOT
       STA PNTR
       LDA EOT+1
       STA PNTR+1
       LDA #3       SIZE IS 3 BYTES
       BNE .2       ...ALWAYS
.9     JMP GT255ERR  VALUE > 255
*--------------------------------
CALC.OFFSET.BYTE
       INY
       LDA ORGN-2,Y
       >SYM SBC,STPNTR
       STA SYMBOL-1,Y
       RTS
*--------------------------------
*      ADD A PRIVATE LABEL
*--------------------------------
ADD.PRIVATE.LABEL
       SEC
       LDA MACLBL
       SBC #7
       STA MACLBL
       STA STPNTR
       LDA MACLBL+1
       SBC #0
       STA MACLBL+1
       STA STPNTR+1
       CMP #8       BELOW $0800?
       BCC .3       YES, NO MORE ROOM
       LDY #6       POINT AT LAST BYTE
.1     LDA SYMBOL+4,Y
       CPY #4
       BCS .2
       LDA ORGN,Y
.2     >SYM STA,STPNTR
       DEY
       BPL .1
       RTS
.3     JMP MFER
*--------------------------------------
MAN
SAVE usr/src/scmasm.30/scmasm.s.symt
LOAD usr/src/scmasm.30/scmasm.s
ASM
