NEW
  AUTO 3,1
*--------------------------------------
*      .MA DIRECTIVE
*--------------------------------
PSMA   LDA PASS     WHICH PASS?
       BNE .2       PASS 2, SO SET FLAG AND IGNORE
       LDA #'Z+1    RIGHT BRACKET CODE
       STA SYMBOL+7
       LDA #0       CLEAR VALUE BYTES
       LDX #3
.1     STA SYMBOL+2,X
       DEX
       BPL .1
       JSR GNNB     GET FIRST CHAR OF MACRO NAME
       LDX #1
       JSR PACK.NAME
       CPX #2       NEED AT LEAST TWO CHARS, COUNTING BRACKET
       BCC .3       NO MACRO NAME
       STX SYMBOL+6 LENGTH
       JSR STSRCH
       BCC .4       DOUBLE DEFN
       JSR STADD    ENTER INTO SYMBOL TABLE
.2     SEC          SET "INSIDE MACRO DEFINITION" FLAG
       ROR FLAG.MA
       RTS          RETURN TO MAIN LEVEL OF ASM
.3     LDY #QNONAM  NO MACRO NAME
       .HS 2C       SKIP NEXT TWO BYTES
.4     LDY #QER4    EXTRA DEF'N
       JMP FIRM.ERROR
*--------------------------------
*      PACK MACRO LINE
*--------------------------------
PACK.MACRO.LINE
       JSR SCAN.TO.OPCODE
       LDX FLAG.MA  IN A MACRO DEF'N?
       BPL D.SET    ...NO, TRY .SE DIRECTIVE
       LDX PASS     WHICH PASS?
       BNE .10      PASS 2
*---PASS 1-----------------------
       BCS .4       ...OPCODE IS NOT A DIRECTIVE
       LDX #DIR.QT.MA
       JSR DIR.SCAN.OR.FAIL
       BCC .2       NOT .MA
.1     LDY #QER2    "BAD OPCODE"
       JMP SOFT.ERROR
.2     JSR DIR.SCAN.OR.FAIL
       BCC .3       NOT .EM
       LDA #0       TERMINATE THE SKELETON
       STA CURRENT.MAJOR.LABEL+1  KILL POSSIBILITY OF LOCAL LABELS
*                               UNTIL ANOTHER MAJOR LABEL
       JSR ADD.CHAR.TO.SKELETON
.11    LSR FLAG.MA
.12    SEC
       RTS
*--------------------------------
.3     JSR DIR.SCAN.OR.FAIL  SEE IF .IN
       BCS .1       YES, SO ILLEGAL!
*      FALL INTO ACCEPTABLE LINE CODE
*--------------------------------
.4     LDY #0       BACK TO BEGINNING OF LINE
       BEQ .5       ...ALWAYS
.55    LDX #$80     COMPRESSED BLANK TOKEN
.6     INX          COUNT THE BLANK
       CPX #$BF     MAX BLANK COUNT?
       BCS .7       YES, OUTPUT TOKEN NOW
       JSR GNC2     GET NEXT CHARACTER
       BCS .7       END OF LINE
       BEQ .6       BLANK, SO COMPRESS IT
       DEY          NON-BLANK, SO BACK UP PNTR
.7     TXA          COMPRESSED BLANK TOKEN
.8     JSR ADD.CHAR.TO.SKELETON
.5     JSR GNC2     GET NEXT CHARACTER
       BCS .9       END OF LINE
       BEQ .55      ...it is a blank
       CMP #']'     MACRO PARAMETER?
       BNE .8       ...NO
       TAX          save ']' in X
       JSR GNC2     GET PARAMETER CODE
       BCS .7       ...eol, add ']' and end
       CMP #']'
       BEQ .8       ...two makes one
       CMP #'#'
       BEQ .81      ...]# is valid parameter
       CMP #'9'+1   HOW ABOUT 1...9
       BCS .82      ...not a parameter
       CMP #'1'
       BCC .82      ...not a parameter
.81    LDX #$7F     valid parameter
.82    DEY          back up char pntr
       JMP .7       go add $7F or ']'
*--------------------------------
.9     LDA #0       TERMINATE THE LINE
       JSR ADD.CHAR.TO.SKELETON
       SEC
       RTS
*---PASS 2-----------------------
*      IF NOT ".EM", JUST LIST THE LINE
.10    BCS .12      ...OPCODE IS NOT A DIRECTIVE
       LDX #DIR.QT.EM
       JSR DIR.SCAN.OR.FAIL
       BCC .12      NOT .EM
       BCS .11      ...ALWAYS
*--------------------------------
*      .SET DIRECTIVE
*--------------------------------
D.SET
       BCS .1            NOT A DIRECTIVE
       LDX #DIR.QT.SE
       JSR DIR.SCAN.OR.FAIL
       BCS .2            FOUND .SE
.1     CLC
       RTS
.2     JSR EXPR.DEFINED  GET VALUE
       JSR GNC.UC.START  CHECK FOR VALID LABEL
       BEQ .6            ...NO LABEL ERROR
       JSR CHECK.LETTER  MUST BE NORMAL LABEL
       BCC .7            ...DOES NOT START WITH A-Z
       JSR PACK
       BCC .7            ...BAD SYMBOL
       JSR STSRCH
       BCC .3            ...IN TABLE ALREADY
       LDA SYMBOL+7
       ORA #$80
       STA SYMBOL+7 SET THE .SE FLAG
       JSR STADD
       JMP .4
.3     LDY #7       CK .SE FLAG
       >SYM LDA,TPTR
       BPL .9       DOUBLE DEF IF NOT SET!
       LDA TPTR     USE SAME PTR AS STADD
       STA PNTR
       LDA TPTR+1
       STA PNTR+1
       LDA PASS     HANDLE FORWARD REFERENCES
       BEQ .5       ...IN PASS ONE
       DEY          POINT AT FLAGS
       >SYM LDA,PNTR
       ORA #$40
       >SYM STA,PNTR
.4     JSR P.EXP.VALUE.DASH     (IF LISTING)
.5     LDY #2       PUT VALUE IN SYMBOL TABLE
.8     LDA EXP.VALUE-2,Y
       >SYM STA,PNTR
       INY
       CPY #6
       BCC .8
       RTS          RETURN TO ASM WITH .CS.
.6     JMP NOLBLERR
.7     JMP ERR.BS
.9     JMP ERR.DBLDF
*--------------------------------
*      ADD CHARACTER TO SKELETON
*--------------------------------
ADD.CHAR.TO.SKELETON
       PHA          SAVE CHAR
  .DO AUXMEM
       LDA EOT+1
       CMP /$C000
       BCC .1
       JMP MFER     MEM FULL ERROR
.1     STA WRAUX
       LDX #0
       PLA
       STA (EOT,X)
       STA WRMAIN
  .ELSE
       LDA EOT
       CMP PP
       LDA EOT+1
       SBC PP+1
       BCC .1       ROOM
       JMP MFER     MEM FULL ERROR
.1     LDX #0
       PLA
       STA (EOT,X)
  .FIN
      >INCD EOT
       RTS
*--------------------------------
*      SCAN TO OPCODE
*--------------------------------
SCAN.TO.OPCODE
       JSR GNC.START  GET FIRST CHAR
       BEQ .2       ...BLANK OR END
       JSR CHECK.COMMENT.CHAR
       BEQ .3       ...YES, IT IS A COMMENT
.1     JSR GNC      SCAN TO A BLANK
       BNE .1       ...NOT BLANK YET
.2     JSR GNNB     SCAN TO NON-BLANK
       BCS .3       ...END OF LINE
       CMP #'.'     DIRECTIVE?
       BNE .3       ...NO
       JSR GNC.UC      GET NEXT BYTE
       CLC          SIGNAL IT IS A DIRECTIVE
       RTS
.3     SEC          SIGNAL IT IS NOT A DIRECTIVE
       RTS
*--------------------------------
*      PROCESS MACRO CALL
*--------------------------------
MACER1 LDY #QNONAM
       .HS 2C
MACER2 LDY #QERR.MACRO
       JMP SOFT.ERROR
*--------------------------------
MACRO.CALL
       LDA #'Z+1    MACRO KEY IN SYMBOL TABLE
       STA SYMBOL+7
       LDX #1
       JSR GNC.UC      GET FIRST CHAR OF MACRO NAME
       JSR PACK.NAME
       CPX #2
       BCC MACER1   ERROR, NO NAME
       STX SYMBOL+6 LENGTH OF NAME
       JSR STSRCH
       BCS MACER2   ERROR, NO SUCH MACRO
       JSR P.ORIGIN
       JSR LIST.SOURCE.IF.LISTING
       JSR GNNB     SCAN TO PARAMETER LIST
       JSR BACKUP.CHAR.PNTR
       LDA MACSTK+1 SAVE PNTR FOR LATER
       PHA
       LDA MACSTK
       PHA
       LDX #0       PROCESS PARAMETER LIST
       LDA #9       FIND 9 PARAMETERS
       STA PARAM.CNT
.1     JSR GET.ONE.PARAMETER
       DEC PARAM.CNT
       BNE .1
.2     LDA WBUF-1,X
       JSR PUSH.MACSTK
       DEX
       BNE .2
       PLA          PUT OLD MACSTK PNTR ON MACRO STACK
       JSR PUSH.MACSTK   (LOW BYTE)
       PLA
       JSR PUSH.MACSTK   (HIGH BYTE)
       LDA SRCP
       JSR PUSH.MACSTK
       LDA SRCP+1
       JSR PUSH.MACSTK
       LDA LF.ALL   save current list option
       JSR PUSH.MACSTK
       LDA CALL.NUM  STACK CURRENT CALL #
       JSR PUSH.MACSTK
       LDA CALL.NUM+1
       JSR PUSH.MACSTK
       CLC          COMPUTE ADDRESS OF SKELETON
       LDA #7
       LDY #6       POINT AT LENGTH OF MACRO NAME
       >SYM ADC,STPNTR    NAME LENGTH+7
       ADC STPNTR
       STA SRCP
       LDA STPNTR+1
       ADC #0
       STA SRCP+1
       LDA LF.MACRO
       ORA LF.ALL        DON'T LIST EXPANSION IF NOT LISTING
       STA LF.ALL
       INC MACRO.LEVEL
      >INCD CALL.CNTR     COUNT THIS MACRO CALL
       LDA CALL.CNTR
       STA CALL.NUM
       LDA CALL.CNTR+1
       STA CALL.NUM+1
       JMP ASM2
*--------------------------------
*      PUSH A BYTE ON MACSTK
*--------------------------------
PUSH.MACSTK
       PHA          SAVE BYTE TO BE PUSHED
  .DO AUXMEM
       LDA MACSTK+1
       CMP /$0800
       BCS .1
  .ELSE
       LDA EOT
       CMP MACSTK
       LDA EOT+1
       SBC MACSTK+1
       BCC .1       STILL ROOM
  .FIN
       JMP MFER     NO ROOM
.1     LDA MACSTK
       BNE .2
       DEC MACSTK+1
.2     DEC MACSTK
       PLA          BYTE TO BE PUSHED
       LDY #0
       STA (MACSTK),Y
       RTS
*--------------------------------
*      GET ONE PARAMETER FROM MACRO CALL LINE
*--------------------------------
GET.ONE.PARAMETER
       JSR GNC
       BEQ .2       SPACE OR EOL, NO MORE PARAMETERS
       CMP #',      COMMA
       BEQ .3       NULL PARAMETER
       CMP #'"      QUOTE
       BEQ .4       QUOTED PARAMETER
.1     STA WBUF,X   NORMAL PARAMETER
       INX
       JSR GNC
       BEQ .2       END OF PARAMETER
       CMP #',      COMMA
       BNE .1       MORE TO PARAMETER
       BEQ .3       END OF PARAMETER
.2     JSR BACKUP.CHAR.PNTR
.3     LDA #0
       STA WBUF,X
       INX
       RTS
.4     JSR GNC         QUOTED PARAMETER
       BCS .3       END OF LINE
       CMP #'"
       BEQ .5       END OF QUOTED PARAMETER
.6     STA WBUF,X
       INX
       BNE .4       ...ALWAYS
.5     JSR GNC
       BEQ .2       END OF PARAMETER LIST
       CMP #',      COMMA
       BEQ .3
       BNE .6       ...ALWAYS
*--------------------------------
*      DIRECTIVE SCAN OR FAIL
*      COMPARE NEXT TWO CHARS WITH TABLE ENTRY
*      ENTER:  FIRST CHAR SET UP BY GNC.UC
*              (X)=OFFSET OF TWO-BYTE ENTRY IN DIR.QTS
*--------------------------------
DIR.SCAN.OR.FAIL
       CMP DIR.QTS,X
       BNE .1       FAIL
       LDY CHAR.PNTR
       LDA WBUF,Y   NEXT CHAR
       AND #$DF     MAP LOWER CASE TO UPPER CASE
       CMP DIR.QTS+1,X
       BNE .1       FAIL
       JSR GNC.UC      SCAN OVER SECOND CHAR
       SEC          SIGNAL SUCCESS
       RTS
.1     CLC          SIGNAL FAILURE
       LDA CURRENT.CHAR  RESTORE (A)
       INX               ADVANCE TO NEXT QUOTE
       INX
       RTS
*--------------------------------
DIR.QTS
DIR.QT.DO .EQ *-DIR.QTS
       .AS /DO/
DIR.QT.EL .EQ *-DIR.QTS
       .AS /EL/
DIR.QT.FI .EQ *-DIR.QTS
       .AS /FI/
DIR.QT.MA .EQ *-DIR.QTS
       .AS /MA/
DIR.QT.EM .EQ *-DIR.QTS
       .AS /EM/
DIR.QT.IN .EQ *-DIR.QTS
       .AS /IN/
DIR.QT.SE .EQ *-DIR.QTS
       .AS /SE/
*--------------------------------------
MAN
SAVE usr/src/scmasm.30/scmasm.s.macro
LOAD usr/src/scmasm.30/scmasm.s
ASM
