[comp.binaries.apple2] QF.SPCLWRDS1.S

tm@polari.UUCP (Toshi Morita) (07/30/90)

This is an include file for QForth.


********************************
* Start special compiler words 1
********************************

*
* Read more of filename - called by READSUB
*

READMORE JSR READFILE ; Read file
 BEQ :MORECHR

 STZ AGAIN ; If no more characters then mark as
 ;   last read

:MORECHR LDA #DATA ; Set up pointer to the start of text
 STA FILEPNTR ;   we've just read so we can
 LDA #/DATA ;   process it
 STA FILEPNTR+1
 RTS

*
* Word "read" - compile text file
*

WORD1 ASC 'read '
 DW READ

AGAIN HEX 00

READ BRK ; Special executable compiler subroutine

 JSR SKIP2SPC ; Skip over this word ("read")
 JSR SKIPSPCS ; Skip to filename to read

 LDA #$20 ; JSR READSUB
 JSR OUTBYTE
 LDA #READSUB
 JSR OUTBYTE
 LDA #/READSUB
 JSR OUTBYTE

 JSR TEXTOUT ; Output text of filename

 TYA
 BEQ :ERROR

 LDA #$00 ; Null-terminate string
 JMP OUTBYTE

:ERROR LDA #$17 ; "READ without filename"
 JMP PRTERR

*

READSUB PLA
 STA PNTR
 PLA
 STA PNTR+1

 INC PNTR
 BNE :SKIPINC
 INC PNTR+1

:SKIPINC LDY #$00 ; Move filename to FILENAME
:LOOP LDA (PNTR),Y
 BEQ :EOL
 STA FILENAME+1,Y
 INY
 BRA :LOOP

:EOL STY FILENAME ; Set up length byte

 JSR GFI ; GET_FILE_INFO

 LDA PARMS+4 ; Make sure it's a text file
 CMP #$04
 BNE :ERROR2

 JSR OPENFILE ; Open the file so we can read it

 SEC ; We've successfully opened file
 ROR FILE ;   so if an error occurs close it
 SEC
 ROR AGAIN

 JSR READMORE ; Read the file

:OUTER LDY #$00 ; Read a string terminated by return into
:LOOP2 LDA (FILEPNTR) ;  input buffer so we can execute it
 STA INPUT,Y

 INC FILEPNTR ; Bump pointer
 BNE :NEXTCHR

 INC FILEPNTR+1 ; If pointer hit end of data buffer...
 LDX FILEPNTR+1
 CPX #/DATA+DATALEN
 BNE :NEXTCHR

 LDA AGAIN ;   and there is more data in file...
 BEQ :EOF

 PHA ;   then read more of file into buffer
 PHY
 JSR READMORE
 PLY
 PLA

:NEXTCHR INY
 CMP #$0D
 BNE :LOOP2

 JSR INTERP ; Execute string
 BRA :OUTER

:EOF STZ FILE ; Clear file open flag
 JSR CLOSFILE ; Close file
 JMP CMDINIT ; So it won't try to execute remaining text

:ERROR2 LDA #$18 ; "Can't READ a non-text file"
 JMP PRTERR

*
* Subroutine for adding words
*

ADDSUB JSR SETCEOS ; Set compiler output to end-of-system

 LDA COUTPUT ; Set up PNTR for ADDWORD call
 STA PNTR3
 LDA COUTPUT+1
 STA PNTR3+1

:LOOP LDA (WORDPNTR) ; Output word text
 CMP #$20
 BEQ :EOL
 CMP #$0D
 BEQ :EOL
 JSR OUTBYTE
 INC WORDPNTR
 BNE :LOOP
 INC WORDPNTR+1
 BRA :LOOP
:EOL LDA #$20 ; Append trailing space
 JSR OUTBYTE

 JMP ADDWORD ; Add word to dictionary
;   (CALCHASH has already been called)

*
* Subroutine for outputting word text
*

TEXTOUT LDY #$00 ; Output variable's name
:LOOP LDA (WORDPNTR),Y
 CMP #$0D
 BEQ :END
 CMP #$20
 BEQ :END
 JSR OUTBYTE
 INY
 BRA :LOOP

:END RTS

*
* Subroutine to resume execution after text string
*

RESUME LDY #$FF
:LOOP INY
 LDA (WORDPNTR),Y
 CMP #$20
 BNE :LOOP
 TYA
 CLC
 ADC WORDPNTR
 TAY
 LDX WORDPNTR+1
 BCC :NOINC
 INX
:NOINC PHX
 PHY
 RTS

*
* Word ":" - Define new word
*

WORD2 ASC ': '
 DW COLON

COLON BRK ; Special executable compiler word

 BIT COMPILE ; Make sure we're not already compiling
 BPL :NOTCOMP
 LDA #$08 ; "Cannot define colon definition
 JMP PRTERR ;  within another colon definition"

:NOTCOMP LDA #$FF ; Set compiling flag and
 STA COMPILE ;  "compile next word" flag
 STA CFLAG1
 RTS

* Word ":" - 2nd half (compiler subroutine)

COLON2 STZ CFLAG1 ; Clear out "Add word" flag
 JSR CHKNUM ; Make sure it isn't a number
 BCC :NOTNUM
 LDA #$09 ; "Cannot define number as new word"
 JMP PRTERR

:NOTNUM JSR CALCHASH ; Make sure it isn't in vocabulary already
 JSR CHKWORD
 BCC :ISNEW
 STZ COMPILE ; So GETSEINIT won't forget last word
 LDA #$0A ; "Word already defined"
 JMP PRTERR

:ISNEW JSR ADDSUB ; Add this word to vocabulary

 LDA COUTPUT ; Calculate pointer to address of routine
 CLC
 ADC #$02
 TAY
 LDA COUTPUT+1
 ADC #$00
 PHA
 TYA
 JSR OUTBYTE
 PLA
 JMP OUTBYTE

*
* Word ";" - End colon definition (compiler subroutine)
*

WORD3 ASC '; '
 DW SEMICLN

SEMICLN BRK ; Special executable compiler subroutine

 LDA COMPILE
 BNE :OK

 LDA #$0B ; "Semicolon without colon"
 JMP PRTERR

:OK LDA #$60 ; Add RTS to colon definition
 JSR OUTBYTE
 STZ COMPILE
 JMP SETEOSC ; Set end-of-system to compiler output

*
* Word "variable" - allocate space for a variable
*

WORD4 ASC 'variable '
 DW VARIABLE

VARIABLE BRK ; Special executable compiler subroutine

 JSR SKIP2SPC ; Skip past this word ("variable")
 JSR SKIPSPCS ; Skip to variable to define
 JSR CHKNUM ; Make sure it isn't a number
 BCC :NOTNUM
 LDA #$12 ; "Cannot define number as variable"
 JMP PRTERR

:NOTNUM LDA #$20 ; JSR VARSUB
 JSR OUTBYTE
 LDA #VARSUB
 JSR OUTBYTE
 LDA #/VARSUB
 JSR OUTBYTE

 JSR TEXTOUT ; Output variable's name

 TYA
 BEQ :ERROR
 LDA #$20
 JMP OUTBYTE

:ERROR LDA #$15 ; "No word following 'variable'"
 JMP PRTERR

*

VARSUB PLA
 STA WORDPNTR
 PLA
 STA WORDPNTR+1

 INC WORDPNTR
 BNE :SKIPINC
 INC WORDPNTR+1

:SKIPINC JSR CALCHASH ; Make sure it isn't in vocabulary already
 JSR CHKWORD
 BCC :ISNEW
 LDA #$0A ; "Word already defined"
 JMP PRTERR

:ISNEW JSR SETCEOS ; Set compiler output to end-of-system
 JSR ADDSUB ; Add this word to vocabulary

 LDA COUTPUT ; Calculate pointer to address of routine
 CLC
 ADC #$02
 TAY
 LDA COUTPUT+1
 ADC #$00
 PHA
 TYA
 JSR OUTBYTE
 PLA
 JSR OUTBYTE

 LDA COUTPUT ; Calculate variable location
 CLC
 ADC #$07
 STA PNTR
 LDA COUTPUT+1
 ADC #$00
 STA PNTR+1

 LDA #$A0 ; LDY #variable location
 JSR OUTBYTE
 LDA PNTR
 JSR OUTBYTE

 LDA #$A2 ; LDX #/variable location
 JSR OUTBYTE
 LDA PNTR+1
 JSR OUTBYTE

 LDA #$4C ; JMP PUSHDATA
 JSR OUTBYTE
 LDA #PUSHDATA
 JSR OUTBYTE
 LDA #/PUSHDATA
 JSR OUTBYTE

 LDA #$00 ; Reserve space for variable
 JSR OUTBYTE
 JSR OUTBYTE

 JSR SETEOSC ; Set end-of-system to compiler output

 JMP RESUME ; Resume execution after variable text

*
* Word "constant" - create a constant
*

WORD5 ASC 'constant '
 DW CONSTANT

CONSTANT BRK ; Special executable compiler subroutine

 JSR SKIP2SPC ; Skip past this word ("constant")
 JSR SKIPSPCS ; Skip to constant to define
 JSR CHKNUM ; Make sure it isn't a number
 BCC :NOTNUM
 LDA #$13 ; "Cannot define number as constant"
 JMP PRTERR

:NOTNUM LDA #$20 ; JSR CONSTSUB
 JSR OUTBYTE
 LDA #CONSTSUB
 JSR OUTBYTE
 LDA #/CONSTSUB
 JSR OUTBYTE

 JSR TEXTOUT ; Output constant's name

 TYA
 BEQ :ERROR
 LDA #$20
 JMP OUTBYTE

:ERROR LDA #$15 ; "No word following 'constant'"
 JMP PRTERR

*

CONSTSUB PLA
 STA WORDPNTR
 PLA
 STA WORDPNTR+1

 INC WORDPNTR
 BNE :SKIPINC
 INC WORDPNTR+1

:SKIPINC JSR CALCHASH ; Make sure it isn't in vocabulary already
 JSR CHKWORD
 BCC :ISNEW
 LDA #$0A ; "Word already defined"
 JMP PRTERR

:ISNEW JSR SETCEOS ; Set compiler output to end-of-system
 JSR ADDSUB ; Add this word to vocabulary

 LDA COUTPUT ; Calculate pointer to address of routine
 CLC
 ADC #$02
 TAY
 LDA COUTPUT+1
 ADC #$00
 PHA
 TYA
 JSR OUTBYTE
 PLA
 JSR OUTBYTE

 JSR POPDATA ; GET constant value
 STY PNTR
 STX PNTR+1

 LDA #$A0 ; LDY #constant value
 JSR OUTBYTE
 LDA PNTR
 JSR OUTBYTE

 LDA #$A2 ; LDX #/constant value
 JSR OUTBYTE
 LDA PNTR+1
 JSR OUTBYTE

 LDA #$4C ; JMP PUSHDATA
 JSR OUTBYTE
 LDA #PUSHDATA
 JSR OUTBYTE
 LDA #/PUSHDATA
 JSR OUTBYTE

 JSR SETEOSC ; Set end-of-system to compiler output

 JMP RESUME ; Resume execution after constant text

*
* Word "create" - create new word
*

WORD6 ASC 'create '
 DW CREATE

CREATE BRK ; Special executable compiler subroutine

 JSR SKIP2SPC ; Skip past this word ("create")
 JSR SKIPSPCS ; Skip to word to create
 JSR CHKNUM ; Make sure it isn't a number
 BCC :NOTNUM
 LDA #$14 ; "Cannot define number as array"
 JMP PRTERR

:NOTNUM LDA #$20 ; JSR CREATSUB
 JSR OUTBYTE
 LDA #CREATSUB
 JSR OUTBYTE
 LDA #/CREATSUB
 JSR OUTBYTE

 JSR TEXTOUT ; Output constant's name

 TYA
 BEQ :ERROR
 LDA #$20
 JMP OUTBYTE

:ERROR LDA #$15 ; "No word following 'create'"
 JMP PRTERR

*

CREATSUB PLA
 STA WORDPNTR
 PLA
 STA WORDPNTR+1

 INC WORDPNTR
 BNE :SKIPINC
 INC WORDPNTR+1

:SKIPINC JSR CALCHASH ; Make sure it isn't in vocabulary already
 JSR CHKWORD
 BCC :ISNEW
 LDA #$0A ; "Word already defined"
 JMP PRTERR

:ISNEW JSR SETCEOS ; Set compiler output to end-of-system
 JSR ADDSUB ; Add this word to vocabulary

 LDA COUTPUT ; Calculate pointer to address of routine
 CLC
 ADC #$02
 TAY
 LDA COUTPUT+1
 ADC #$00
 TAX
 TYA
 JSR OUTBYTE
 TXA
 JSR OUTBYTE

 LDA COUTPUT ; Calculate address of storage area
 CLC
 ADC #$07
 TAY
 LDA COUTPUT+1
 ADC #$00
 TAX

 LDA #$A0 ; LDY #storage area
 JSR OUTBYTE
 TYA
 JSR OUTBYTE

 LDA #$A2 ; LDX #/storage area
 JSR OUTBYTE
 TXA
 JSR OUTBYTE

 LDA #$4C ; JMP PUSHDATA
 JSR OUTBYTE
 LDA #PUSHDATA
 JSR OUTBYTE
 LDA #/PUSHDATA
 JSR OUTBYTE

 JSR SETEOSC ; Set end-of-system to compiler output

 JMP RESUME ; Resume execution after constant text

*
* Word "allot" - allot space for data
*

WORD7 ASC 'allot '
 DW ALLOT

ALLOT JSR POPDATA ; Figure out how many bytes to allot
 TYA
 CLC
 ADC EOSPNTR
 STA EOSPNTR
 TXA
 ADC EOSPNTR+1
 STA EOSPNTR+1
 RTS

*
* Word "," - Compile stack value into next two bytes
*

WORD8 ASC ', '
 DW COMMA

COMMA JSR SETCEOS ; Set compiler output to end-of-system
 JSR POPDATA
 TYA
 JSR OUTBYTE
 TXA
 JSR OUTBYTE
 JMP SETEOSC ; Set end-of-system to compiler output

*
* Word "c," - Compile stack value into next byte
*

WORD9 ASC 'c, '
 DW CCOMMA

CCOMMA JSR SETCEOS ; Set compiler output to end-of-system
 JSR POPDATA
 TYA
 JSR OUTBYTE
 JMP SETEOSC ; Set end-of-system to compiler output


*
* Word "forget" - undefine words
*

WORD10 ASC 'forget '
 DW FORGET

FORGET BRK ; Special executable compiler subroutine

 JSR SKIP2SPC ; Skip past this word ("forget")
 JSR SKIPSPCS ; Skip to word to forget
 JSR CHKNUM ; Make sure it isn't a number
 BCC :NOTNUM
 LDA #$16 ; "Cannot forget number 'xxx'"
 JMP PRTERR

:NOTNUM LDA #$20 ; JSR FRGTSUB
 JSR OUTBYTE
 LDA #FRGTSUB
 JSR OUTBYTE
 LDA #/FRGTSUB
 JSR OUTBYTE

 JSR TEXTOUT ; Output word's name

 TYA
 BEQ :ERROR
 LDA #$20
 JMP OUTBYTE

:ERROR LDA #$15 ; "No word following 'forget'"
 JMP PRTERR

*

FRGTSUB PLA
 STA WORDPNTR
 PLA
 STA WORDPNTR+1

 INC WORDPNTR
 BNE :SKIPINC
 INC WORDPNTR+1

:SKIPINC JSR CALCHASH ; Calculate hash of word
 JSR CHKWORD ; Make sure it's in dictionary
 BCS :LOOP

 LDA #$07 ; "Word 'xxx' not found"
 JMP PRTERR

:LOOP JSR FRGTLAST ; Forget last word

 LDY #$02 ; Until we forget the one we want
 LDA (LISTPNTR),Y
 CMP PNTR2
 BNE :LOOP
 INY
 LDA (LISTPNTR),Y
 CMP PNTR2+1
 BNE :LOOP

 LDA PNTR2 ; Reset compiler end-of-system
 STA EOSPNTR ;   and reclaim space
 LDA PNTR2+1
 STA EOSPNTR+1


 JMP RESUME ; Resume execution after constant text

********************************
* End special compiler words 1
********************************