Thursday, August 6, 2020

Commodore 64 BASIC CRUNCH Routine Commented

The disassembled code here is from
Commodore 64 ROM.

The comments and intermediate labels
are mine.

Together they are useful.

Placing this here as is for reference.
I found this exercise necessary when
implementing my hires extensions for C64
including a patch of this routine.

        ; C64 crunch is A57C-A612
        ; C64 tokens are A09E-A19D
crunch ; from C64 ROM
       ; INPUT: PETASCII of entered line is at buffer $0200, ending with #$00 null character
       ; OUTPUT: tokenizes in place entire line, ending line with #$00 null character
       ; HINT: because of tokens, result is smaller than original so can modify in place
         LDX $7A        ; source buffer index
         LDY #$04       ; storage index starts at 4 (4+$1FB+1 = $200)
         STY $0F        ; set not DATA flag (4=NOT, 0=DATA)
.go      LDA $0200,X    ; retrieve next character from input buffer
         BPL .lowch     ; branch if 00-7F
         CMP #$FF       ; PI?
         BEQ .store     ; branch if PI, already tokenized
         INX            ; advance source index
         BNE .go        ; always skip initial character 80-FE, as X shouldn't ever wrap to 0
.lowch   CMP #$20       ; compare to ASCII space
         BEQ .store     ; branch if space, store literal
         STA $08        ; no, store character, non-zero = not REMark
         CMP #$22       ; compare to ASCII quote
         BEQ .literal   ; branch if string, store literal characters instead of matchng tokens
         BIT $0F        ; test if in DATA statement
         BVS .store     ; branch if in DATA statement, store literal characters instead of matching tokens
         CMP #$3F       ; compare to ASCII question mark
         BNE .chkzero   ; no, skip next part
         LDA #$99       ; replace question mark with token PRINT
         BNE .store     ; unconditional branch, store token
.chkzero CMP #$30       ; compare to ASCII zero digit
         BCC .scantbl   ; branch if less
         CMP #$3C       ; compare to ASCII less than
         BCC .store     ; branch if less, so branch if numeric or colon or semi-colon, store literal character
.scantbl STY $71        ; save storage offset index
         LDY #$00       ; initialize token table byte index to zero
         STY $0B        ; initialize token number to zero
         DEY            ; cancel out the next increment for loop beginning with decrement
         STX $7A        ; save source index
         DEX            ; cancel out the next increment for loop beginning with decrement
.advance INY            ; advance token table index
         INX            ; advance source index
.scanch  LDA $0200,X    ; retrieve character from buffer
         SEC            ; prepare for subtraction
         SBC $A09E,Y    ; compare to Commodore token table
         BEQ .advance   ; branch if character match, look for more matches
         CMP #$80       ; end of token?
         BNE .scannxt   ; branch if not end of token, mismatch, so get ready to check next token
         ORA $0B        ; match! combine zero based token number with $80 high bit set for storage
.storaty LDY $71        ; retrive storage offset index
.store   INX            ; advance input index
         INY            ; advance output index
         STA $01FB,Y    ; store token or character
         LDA $01FB,Y    ; set Z flag if end of line
         BEQ .endline   ; branch if end of line, finish up
         SEC            ; prepare for subtraction
         SBC #$3A       ; subtract ASCII colon
         BEQ .setf      ; branch if colon
         CMP #$49       ; DATA?
         BNE .skipset   ; skip setting flag if not DATA
.setf    STA $0F        ; $49 if DATA, or $00 if colon
.skipset SEC            ; prepare for subtraction
         SBC #$55       ; REM?
         BNE .go        ; branch if not REM to get next character
         STA $08        ; store flag zero = REM
.litloop LDA $0200,X    ; retrieve next character from input
         BEQ .store     ; branch if end of line
         CMP $08        ; compare to token that got us in this loop (e.g. 0x22 quote), or 0x00 (REM)
         BEQ .store     ; branch if REMark end of line
.literal INY            ; advance destination index
         STA $01FB,Y    ; store in buffer
         INX            ; advance source index
         BNE .litloop   ; repeat getting next character
.scannxt LDX $7A        ; retrieve source index
         INC $0B        ; advance token number
.endtok  INY            ; advance destination index
         LDA $A09D,Y    ; retrieve character from token table
         BPL .endtok    ; loop until find end of token
         LDA $A09E,Y    ; retrieve next character from token table
         BNE .scanch    ; branch if not end of token table
         LDA $0200,X    ; re-retrieve character from input buffer
         BPL .storaty   ; branch if character 00-7F, should be if got here, no token match
.endline STA $01FD,Y    ; store end of line nul character $00
         DEC $7B        ; update TXTPTR
         LDA #$FF       ;  to point to
         STA $7A        ;  $01FF
         RTS            ; done