mirror of
https://github.com/MajenkoProjects/pdp11-bbcbasic.git
synced 2026-08-23 20:21:33 +01:00
Original import of base code
This commit is contained in:
+626
@@ -0,0 +1,626 @@
|
||||
; > Tokens
|
||||
; Token table - ok
|
||||
; Tokeniser - ok
|
||||
; Detokeniser - ok
|
||||
; 08-Mar-2009: Tokeniser sped up using offsets for each initial letter, linenums tokenised.
|
||||
; 09-Mar-2009: LineFind written.
|
||||
; Tokeniser can be sped up if search terminates when initial letter no longer matches
|
||||
; 24-Jul-2013: Fixed bug where '*' turned off tokenising in middle of statement
|
||||
; 07-Dec-2013: TokenFind written.
|
||||
; 14-Jul-2017: Tokeniser optimised, returns R3=length, R4=>string to match rest of interpreter
|
||||
; 08-May-2020: TokenFind doesn't skip <cr> at end of zero-length lines.
|
||||
; 09-May-2020: PROC@LOAD, FN@SAVE allowed - @ is valid identifier character.
|
||||
; IF thing THEN var=1:IF thing THEN =1 doesn't tokenise the number
|
||||
; Tokeniser optimised by calling EvalCheckDigit and VarCheckChar.
|
||||
; 18-Mar-2024: Added SLOWTOKEN option, spaces don't reset tokeniser so ON ERROR PAGE= works.
|
||||
; 27-Apr-2025: End of hex string steps back so, eg &12OR3 tokenises correctly.
|
||||
; 25-Nov-2025: Bit of optimisation of tokeniser when token matched.
|
||||
; REM/DATA only turn tokeniser off at start of statement, allows LOCAL DATA:...
|
||||
; Two-byte tokens possible.
|
||||
|
||||
; Acorn-style token table
|
||||
; =======================
|
||||
; string, token, flag
|
||||
;
|
||||
; Token flag:
|
||||
; Bit 0 - Conditional tokenisation (don't tokenise if followed by an alphabetic character).
|
||||
; Bit 1 - Not start of statement.
|
||||
; Bit 2 - Now middle of statement (command with parameters)
|
||||
; Bit 3 - Expect a line number (after a GOTO, etc...).
|
||||
; Bit 4 - Pseudo variable - add &40 token if at start of statement (external: hex number).
|
||||
; Bit 5 - FN/PROC keyword - don't tokenise name of the subroutine.
|
||||
; Bit 6 - Don't tokenise rest of line (REM, DATA, etc...)
|
||||
; Bit 7 - 2-byte token (external: quote toggle)
|
||||
|
||||
.TokenTable
|
||||
.tknA EQUB "AND" ,&80,&02 ; 00000010
|
||||
EQUB "ABS" ,&94,&02 ; 00000010
|
||||
EQUB "ACS" ,&95,&02 ; 00000010
|
||||
EQUB "ADVAL" ,&96,&02 ; 00000010
|
||||
EQUB "ASC" ,&97,&02 ; 00000010
|
||||
EQUB "ASN" ,&98,&02 ; 00000010
|
||||
EQUB "ATN" ,&99,&02 ; 00000010
|
||||
EQUB "AUTO" ,&C6,&02 ; 00000010 ; was &0A
|
||||
.tknB EQUB "BGET" ,&9A,&03 ; 00000011
|
||||
EQUB "BPUT" ,&D5,&07 ; 00000111
|
||||
.tknC EQUB "COLOUR" ,&FB,&06 ; 00000110
|
||||
EQUB "CALL" ,&D6,&06 ; 00000110
|
||||
EQUB "CHAIN" ,&D7,&06 ; 00000110
|
||||
EQUB "CHR$" ,&BD,&02 ; 00000010
|
||||
EQUB "CLEAR" ,&D8,&03 ; 00000011
|
||||
EQUB "CLOSE" ,&D9,&07 ; 00000111
|
||||
EQUB "CLG" ,&DA,&03 ; 00000011
|
||||
EQUB "CLS" ,&DB,&03 ; 00000011
|
||||
EQUB "COS" ,&9B,&02 ; 00000010
|
||||
EQUB "COUNT" ,&9C,&03 ; 00000011
|
||||
EQUB "COLOR" ,&FB,&06 ; 00000110
|
||||
.tknD EQUB "DATA" ,&DC,&42 ; 01000010
|
||||
EQUB "DEG" ,&9D,&02 ; 00000010
|
||||
EQUB "DEF" ,&DD,&02 ; 00000010
|
||||
EQUB "DELETE" ,&C7,&02 ; 00000010 ; was &0A
|
||||
EQUB "DIV" ,&81,&02 ; 00000010
|
||||
EQUB "DIM" ,&DE,&06 ; 00000110
|
||||
EQUB "DRAW" ,&DF,&06 ; 00000110
|
||||
.tknE EQUB "ENDPROC" ,&E1,&03 ; 00000011
|
||||
EQUB "END" ,&E0,&03 ; 00000011
|
||||
EQUB "ENVELOPE",&E2,&06 ; 00000110
|
||||
EQUB "ELSE" ,&8B,&08 ; 00001000
|
||||
EQUB "EVAL" ,&A0,&02 ; 00000010
|
||||
EQUB "ERL" ,&9E,&03 ; 00000011
|
||||
EQUB "ERROR" ,&85,&00 ; 00000000
|
||||
EQUB "EOF" ,&C5,&03 ; 00000011
|
||||
EQUB "EOR" ,&82,&02 ; 00000010
|
||||
EQUB "ERR" ,&9F,&03 ; 00000011
|
||||
EQUB "EXP" ,&A1,&02 ; 00000010
|
||||
EQUB "EXT" ,&A2,&03 ; 00000011
|
||||
; EQUB "EDIT" ,&CE,&02 ; 00000010 ; was &0A
|
||||
.tknF EQUB "FOR" ,&E3,&06 ; 00000110
|
||||
EQUB "FALSE" ,&A3,&03 ; 00000011
|
||||
EQUB "FN" ,&A4,&22 ; 00100010
|
||||
.tknG EQUB "GOTO" ,&E5,&0E ; 00001110
|
||||
EQUB "GET$" ,&BE,&02 ; 00000010
|
||||
EQUB "GET" ,&A5,&02 ; 00000010
|
||||
EQUB "GOSUB" ,&E4,&0E ; 00001110
|
||||
EQUB "GCOL" ,&E6,&06 ; 00000110
|
||||
.tknH EQUB "HIMEM" ,&93,&17 ; 00010111
|
||||
.tknI EQUB "INPUT" ,&E8,&06 ; 00000110
|
||||
EQUB "IF" ,&E7,&06 ; 00000110
|
||||
EQUB "INKEY$" ,&BF,&02 ; 00000010
|
||||
EQUB "INKEY" ,&A6,&02 ; 00000010
|
||||
EQUB "INT" ,&A8,&02 ; 00000010
|
||||
EQUB "INSTR(" ,&A7,&02 ; 00000010
|
||||
.tknJ
|
||||
.tknK
|
||||
.tknL EQUB "LIST" ,&C9,&02 ; 00000010 ; was &0A
|
||||
EQUB "LINE" ,&86,&02 ; 00000010
|
||||
EQUB "LOAD" ,&C8,&06 ; 00000110
|
||||
EQUB "LOMEM" ,&92,&17 ; 00010111
|
||||
EQUB "LOCAL" ,&EA,&06 ; 00000110
|
||||
EQUB "LEFT$(" ,&C0,&02 ; 00000010
|
||||
EQUB "LEN" ,&A9,&02 ; 00000010
|
||||
EQUB "LET" ,&E9,&00 ; 00000000
|
||||
EQUB "LOG" ,&AB,&02 ; 00000010
|
||||
EQUB "LN" ,&AA,&02 ; 00000010
|
||||
.tknM EQUB "MID$(" ,&C1,&02 ; 00000010
|
||||
EQUB "MODE" ,&EB,&06 ; 00000110
|
||||
EQUB "MOD" ,&83,&02 ; 00000010
|
||||
EQUB "MOVE" ,&EC,&06 ; 00000110
|
||||
.tknN EQUB "NEXT" ,&ED,&06 ; 00000110
|
||||
EQUB "NEW" ,&CA,&03 ; 00000011
|
||||
EQUB "NOT" ,&AC,&02 ; 00000010
|
||||
.tknO EQUB "OLD" ,&CB,&03 ; 00000011
|
||||
EQUB "ON" ,&EE,&06 ; 00000110
|
||||
EQUB "OFF" ,&87,&02 ; 00000010
|
||||
EQUB "OR" ,&84,&02 ; 00000010
|
||||
EQUB "OPENIN" ,&8E,&02 ; 00000010
|
||||
EQUB "OPENOUT" ,&AE,&02 ; 00000010
|
||||
EQUB "OPENUP" ,&AD,&02 ; 00000010
|
||||
EQUB "OSCLI" ,&FF,&06 ; 00000110
|
||||
.tknP EQUB "PRINT" ,&F1,&06 ; 00000110
|
||||
EQUB "PAGE" ,&90,&17 ; 00010111
|
||||
EQUB "PTR" ,&8F,&17 ; 00010111
|
||||
EQUB "PI" ,&AF,&03 ; 00000011
|
||||
EQUB "PLOT" ,&F0,&06 ; 00000110
|
||||
EQUB "POINT(" ,&B0,&02 ; 00000010
|
||||
EQUB "PROC" ,&F2,&26 ; 00100110
|
||||
EQUB "POS" ,&B1,&03 ; 00000011
|
||||
EQUB "PUT" ,&CE,&02 ; 00000010
|
||||
.tknQ
|
||||
; EQUB "QUIT" ,&98,&86 ; 10000110
|
||||
.tknR EQUB "RETURN" ,&F8,&03 ; 00000011
|
||||
EQUB "REPEAT" ,&F5,&02 ; 00000010
|
||||
EQUB "REPORT" ,&F6,&03 ; 00000011
|
||||
EQUB "READ" ,&F3,&06 ; 00000110
|
||||
EQUB "REM" ,&F4,&42 ; 01000010
|
||||
EQUB "RUN" ,&F9,&03 ; 00000011
|
||||
EQUB "RAD" ,&B2,&02 ; 00000010
|
||||
EQUB "RESTORE" ,&F7,&0E ; 00001110
|
||||
EQUB "RIGHT$(" ,&C2,&02 ; 00000010
|
||||
EQUB "RND" ,&B3,&03 ; 00000011
|
||||
EQUB "RENUMBER",&CC,&02 ; 00000010 ; was &0A
|
||||
.tknS EQUB "STEP" ,&88,&02 ; 00000010
|
||||
EQUB "SAVE" ,&CD,&06 ; 00000110
|
||||
EQUB "SGN" ,&B4,&02 ; 00000010
|
||||
EQUB "SIN" ,&B5,&02 ; 00000010
|
||||
EQUB "SQR" ,&B6,&02 ; 00000010
|
||||
EQUB "SPC" ,&89,&02 ; 00000010
|
||||
EQUB "STR$" ,&C3,&02 ; 00000010
|
||||
EQUB "STRING$(",&C4,&02 ; 00000010
|
||||
EQUB "SOUND" ,&D4,&06 ; 00000110
|
||||
EQUB "STOP" ,&FA,&03 ; 00000011
|
||||
; EQUB "SYS" ,&99,&86 ; 10000110
|
||||
.tknT EQUB "TAN" ,&B7,&02 ; 00000010
|
||||
EQUB "THEN" ,&8C,&08 ; 00001000
|
||||
EQUB "TO" ,&B8,&02 ; 00000010
|
||||
EQUB "TAB(" ,&8A,&02 ; 00000010
|
||||
EQUB "TRACE" ,&FC,&0E ; 00001110
|
||||
EQUB "TIME" ,&91,&17 ; 00010111
|
||||
EQUB "TRUE" ,&B9,&03 ; 00000011
|
||||
.tknU EQUB "UNTIL" ,&FD,&06 ; 00000110
|
||||
EQUB "USR" ,&BA,&02 ; 00000010
|
||||
.tknV EQUB "VDU" ,&EF,&06 ; 00000110
|
||||
EQUB "VAL" ,&BB,&02 ; 00000010
|
||||
EQUB "VPOS" ,&BC,&03 ; 00000011
|
||||
.tknW EQUB "WIDTH" ,&FE,&06 ; 00000110
|
||||
EQUB "PAGE" ,&D0,&02 ; 00000010
|
||||
EQUB "PTR" ,&CF,&02 ; 00000010
|
||||
EQUB "TIME" ,&D1,&02 ; 00000010
|
||||
EQUB "LOMEM" ,&D2,&02 ; 00000010
|
||||
EQUB "HIMEM" ,&D3,&02 ; 00000010
|
||||
EQUB "Missing ",&8D,&00 ; 00000000
|
||||
EQUB &00
|
||||
ALIGN
|
||||
#ifndef SLOWTOKEN
|
||||
.TokenOffsets
|
||||
EQUW tknA-TokenTable
|
||||
EQUW tknB-TokenTable
|
||||
EQUW tknC-TokenTable
|
||||
EQUW tknD-TokenTable
|
||||
EQUW tknE-TokenTable
|
||||
EQUW tknF-TokenTable
|
||||
EQUW tknG-TokenTable
|
||||
EQUW tknH-TokenTable
|
||||
EQUW tknI-TokenTable
|
||||
EQUW tknJ-TokenTable
|
||||
EQUW tknK-TokenTable
|
||||
EQUW tknL-TokenTable
|
||||
EQUW tknM-TokenTable
|
||||
EQUW tknN-TokenTable
|
||||
EQUW tknO-TokenTable
|
||||
EQUW tknP-TokenTable
|
||||
EQUW tknQ-TokenTable
|
||||
EQUW tknR-TokenTable
|
||||
EQUW tknS-TokenTable
|
||||
EQUW tknT-TokenTable
|
||||
EQUW tknU-TokenTable
|
||||
EQUW tknV-TokenTable
|
||||
EQUW tknW-TokenTable
|
||||
#endif
|
||||
|
||||
.TokeniseEVAL
|
||||
mov r4,-(sp) ; Save destination
|
||||
mov #2,r2 ; Set flags to 'within statement'
|
||||
br TokenLoop
|
||||
|
||||
; Tokenise entered line and line number
|
||||
; -------------------------------------
|
||||
; On entry, r5=>untokenised source, may have leading spaces
|
||||
; On exit, R5=>after <cr> at end of input line
|
||||
; R4=>start of tokenised line
|
||||
; R3= length of tokenised line excluding <cr>
|
||||
; R2= line number, EQ/NE set
|
||||
;
|
||||
.TokeniseLine
|
||||
jsr pc,ReadLineNumber ; r4=line number (CC) or zero (CS)
|
||||
bcs TokeniseLineNoNum ; No line number entered
|
||||
mov r4,SV_LINE ; Set current input line number
|
||||
.TokeniseLineNoNum ; r5=>start or line or after line number
|
||||
adr SV_INPUT,r4 ; r4=>dest in input buffer
|
||||
; Fall through into tokeniser
|
||||
|
||||
; Tokeniser
|
||||
; =========
|
||||
; On entry, R5=>untokenised text
|
||||
; R4=>destination buffer
|
||||
; Enter at Tokenise - use LISTO options
|
||||
; TokenStrip - strip leading spaces
|
||||
; TokenNoStrip - keep leading spaces
|
||||
; Uses R3=>token table address
|
||||
; R2= current tokeniser flags
|
||||
; R1= new tokeniser flags
|
||||
; R0= character
|
||||
; On exit, R5=>after <cr> at end of input line
|
||||
; R4=>start of tokenised line
|
||||
; R3= length of tokenised line excluding <cr>
|
||||
; R2= line number, EQ/NE
|
||||
;
|
||||
.Tokenise
|
||||
movb SV_OPTIONS,r0
|
||||
beq TokenNoStrip ; LISTO=0, don't strip leading spaces
|
||||
.TokeniseStrip
|
||||
cmpb (r5)+,#ASC" "
|
||||
beq TokeniseStrip ; Skip leading spaces
|
||||
dec r5
|
||||
.TokenNoStrip
|
||||
mov r4,-(sp) ; Save destination
|
||||
.TokenZero
|
||||
clr r2 ; Clear tokeniser flags
|
||||
.TokenNext
|
||||
.TokenLoop
|
||||
movb (r5)+,r0 ; Get current character
|
||||
cmp r0,#9
|
||||
beq TokenNext ; Skip any embedded TABs
|
||||
dec r5 ; Point to current character
|
||||
bit #&F0,r2 ; Any skip flags set?
|
||||
bne TokenByte ; Inside quote/REM/PROCFN/hex
|
||||
bit #&08,r2 ; Is a line number expected?
|
||||
beq TokenNotLine ; No, try to tokenise
|
||||
jsr pc,TokeniseNumber ; Tokenise line number
|
||||
; CC=not a number, r5=>this character, r0=character
|
||||
; CS=number entered, r5=>next character
|
||||
bcs TokenLoop
|
||||
.TokenNotLine
|
||||
cmp r0,#ASC"A" ; Tokens start with a letter
|
||||
bcs TokenByte ; <'A', enter character
|
||||
cmp r0,#ASC"X"
|
||||
bcc TokenByte ; >'W', enter character
|
||||
jsr pc,TokenSearch ; Search token table
|
||||
; Returns r5=>before next character
|
||||
; r4= unchanged, output pointer
|
||||
; r2= unchanged, current tokeniser flags
|
||||
; r1= new tokeniser flag
|
||||
; r0= byte to enter, token or char
|
||||
;bpl TokenWord0 ; Not a two-byte token
|
||||
;movb #&C8,(r4)+ ; Insert prefix byte
|
||||
;bic #128,r1
|
||||
;.TokenWord0
|
||||
bit #2,r2 ; Are we at the start of statement?
|
||||
bne TokenWord1 ; No, enter token/char
|
||||
bit #16,r1 ; Is this a pseudo-variable?
|
||||
beq TokenWord2 ; No, enter unchanged
|
||||
add #&40,r0 ; Convert token to command token
|
||||
.TokenWord1
|
||||
bic #&40,r2 ; Middle of statement, don't turn tokeniser off
|
||||
.TokenWord2
|
||||
mov r1,r2 ; Copy new flags to current flags
|
||||
.TokenByte
|
||||
inc r5 ; Increment input pointer
|
||||
movb r0,(r4)+ ; Enter byte in output buffer
|
||||
bmi TokenLoop ; Token entered, loop back
|
||||
cmp r0,#ASC" " ; At end of line?
|
||||
beq TokenSpace ; Terminate PROC/FN, hex, LineNum
|
||||
bcc TokenNotCR ; Not end of line, jump to check character
|
||||
;movb SV_OPTIONS,r0
|
||||
;beq TokenLineEnd ; LISTO=0, don't strip trailing spaces
|
||||
;strip trailing spaces
|
||||
;
|
||||
.TokenLineEnd
|
||||
movb #&FF,(r4) ; Put &FF after <cr>
|
||||
movb #13,-(r4) ; Ensure <cr> terminator
|
||||
; R5=>after <cr> at end of source, for textload
|
||||
mov r4,r3 ; R3=>end of string
|
||||
mov (sp)+,r4 ; R4=>start of string
|
||||
sub r4,r3 ; R3=length of string
|
||||
mov SV_LINE,r2 ; R2=line number, EQ/NE set
|
||||
rts pc
|
||||
|
||||
.TokenNotCR
|
||||
cmp r0,#34 ; Is char quote?
|
||||
bne TokenNotQuote ; No, jump to next check
|
||||
add #128,r2 ; Toggle quote flag
|
||||
br TokenLoop ; Loop back to continue tokenising
|
||||
|
||||
.TokenNotQuote
|
||||
bit #&C0,r2 ; Inside quotes or REM/DATA/*cmd?
|
||||
bne TokenLoop ; Loop back, ignoring character
|
||||
cmp r0,#&3A ; Is char colon?
|
||||
beq TokenZero ; Loop back to reset to start of statement
|
||||
|
||||
cmp r0,#ASC"*" ; Is char star?
|
||||
bne TokenNotStar ; No, jump to next check
|
||||
bit #&02,r2 ; At start of statement?
|
||||
bne TokenLoop ; No, treat as normal character
|
||||
mov #&40,r2 ; Treat rest of line as comment
|
||||
br TokenLoop ; Jump back to continue scanning line
|
||||
|
||||
.TokenNotStar
|
||||
bis #&02,r2 ; Set 'not at start of statement'
|
||||
cmp r0,#ASC"&" ; Is char hex number?
|
||||
bne TokenNotHex ; No, jump to next check
|
||||
mov #&10,r2 ; Set 'scanning hex number'
|
||||
br TokenLoop ; Continue scanning line
|
||||
|
||||
.TokenNotHex
|
||||
bit #&20,r2 ; Scanning PROC/FN?
|
||||
bne TokenPROCFN
|
||||
bit #&10,r2 ; Scanning hex?
|
||||
bne TokenHex
|
||||
cmp #ASC"@",r0 ; Digits and punctuation, continue scanning
|
||||
br TokenCheckEnd
|
||||
.TokenHex
|
||||
jsr pc,CheckHexDigit ; Keep going through hex digits
|
||||
bcc TokenLoop ; Still a hex character
|
||||
dec r5 ; Step back so eg &12OR3 tokenises
|
||||
dec r4
|
||||
br TokenSpace
|
||||
.TokenPROCFN
|
||||
jsr pc,VarChkChar ; Still identifier, continue scanning
|
||||
.TokenCheckEnd
|
||||
bcc TokenLoop ; Loop for next PROC/FN, Hex, LineNum character
|
||||
.TokenSpace
|
||||
bic #&30,r2 ; Clear PROC/FN, Hex flags
|
||||
br TokenLoop
|
||||
|
||||
.TokeniseNumber
|
||||
mov r4,-(sp) ; Save output pointer
|
||||
jsr pc,ReadLineNumberHere ; Read number to R3/R4, already skipped spaces
|
||||
mov r4,r1 ; R1=line number
|
||||
mov (sp)+,r4 ; Get output pointer back
|
||||
bcs TokenNotNumber ; Not a valid line number, not a digit or too big
|
||||
mov r1,r2
|
||||
movb #&8D,(r4)+ ; Line number marker
|
||||
swab r2
|
||||
ror r2
|
||||
ror r2
|
||||
bic #&FFCF,r2
|
||||
mov r1,r0
|
||||
bic #&FF3F,r0
|
||||
bis r0,r2
|
||||
ror r2
|
||||
ror r2
|
||||
mov #&14,r0
|
||||
xor r0,r2
|
||||
mov #3,r0
|
||||
swab r1
|
||||
br TokenNumLp2
|
||||
.TokenNumLp1
|
||||
mov r1,r2
|
||||
bic #&FFC0,r2
|
||||
.TokenNumLp2
|
||||
bis #&40,r2
|
||||
movb r2,(r4)+
|
||||
swab r1
|
||||
dec r0
|
||||
bne TokenNumLp1
|
||||
;mov r4,r4 ; Update output pointer
|
||||
mov #8,r2 ; Still expecting numbers
|
||||
sec ; CS=line number returned
|
||||
rts pc
|
||||
.TokenNotNumber
|
||||
clc ; CC=no line number
|
||||
rts pc
|
||||
|
||||
; Search token table
|
||||
; ==================
|
||||
; On entry, R5=>input string to match
|
||||
; R4=>dest
|
||||
; R2= current flags
|
||||
; R0= current char
|
||||
; On exit, R5=>last char
|
||||
; R4=unchanged
|
||||
; R3 corrupted
|
||||
; R2=old flags
|
||||
; R1=new flags
|
||||
; R0=token or character
|
||||
; if token matched, R0=token, R5=>end of matched string, MI/EQ from new flags
|
||||
; if not matched, R0=byte, R5=>current char, MI/EQ from current flags
|
||||
; Caller doesn't check C/NC or other flags
|
||||
.TokenSearch
|
||||
#ifndef SLOWTOKEN
|
||||
adr TokenOffsets-2*ASC"A",r3
|
||||
asl r0
|
||||
add r0,r3 ; r3=>offset for initial character
|
||||
mov (r3),r0
|
||||
adr TokenTable,r3
|
||||
add r0,r3 ; r3=>start of tokens for this character
|
||||
#else
|
||||
adr TokenTable,r3 ; r3=>start of token table
|
||||
#endif
|
||||
;
|
||||
.SearchTable
|
||||
mov r5,r1 ; Save source pointer
|
||||
.SearchLoop
|
||||
movb (r5),r0 ; Get source character
|
||||
cmpb r0,(r3) ; Compare with token character
|
||||
beq SearchMatch ; Match, check if full match
|
||||
cmp r0,#ASC"." ; Abbreviation?
|
||||
beq SearchDot ; Jump to match abbreviation
|
||||
.SearchNext
|
||||
inc r3 ; Step past this token
|
||||
movb (r3),r0
|
||||
bpl SearchNext ; Loop until token byte
|
||||
inc r3 ; Step past token byte
|
||||
.SearchNextBack
|
||||
mov r1,r5 ; Restore source pointer
|
||||
inc r3 ; Step past flag to next token
|
||||
cmpb (r5),(r3) ; Do initial characters still match?
|
||||
#ifndef SLOWTOKEN
|
||||
beq SearchLoop ; Yes, search next token
|
||||
#else
|
||||
bcc SearchLoop ; Yes, search next token
|
||||
#endif
|
||||
movb (r5),r0 ; Get first char back
|
||||
mov r2,r1 ; new flags=old flags
|
||||
rts pc
|
||||
; R0=char, R1=old flag, R2=old flag, R3=corrupted, R4=preserved, R5=>current char
|
||||
; flags=set from token flags
|
||||
|
||||
.SearchFound
|
||||
dec r5 ; Point to last character of source
|
||||
.SearchDot
|
||||
;inc r3 ; Step to end of token
|
||||
;movb (r3),r0
|
||||
movb (r3)+,r0 ; Step to end of token
|
||||
bpl SearchDot ; Loop until token byte fetched
|
||||
;inc r3 ; Step to flag byte
|
||||
movb (r3),r1 ; Get new flags
|
||||
;sec ; Caller never checks C/NC
|
||||
rts pc
|
||||
; R0=token, R1=new flag, R2=old flag, R3=corrupted, R4=preserved, R5=>last char
|
||||
; flags=CS, flags set from token flag
|
||||
|
||||
.SearchMatch
|
||||
inc r5 ; Step to next source char
|
||||
inc r3 ; Step to next token char
|
||||
;movb (r3),r0 ; Get next byte
|
||||
tstb (r3) ; Test next byte
|
||||
bpl SearchLoop ; Not a token, loop to check next character
|
||||
;inc r3 ; Point to flag
|
||||
;bitb #1,(r3) ; Needs nonalpha terminator?
|
||||
bitb #1,1(r3) ; Needs nonalpha terminator?
|
||||
beq SearchFound ; No nonalpha needed, token matched
|
||||
movb (r5),r0 ; Get following source character
|
||||
cmp r0,#ASC"A"
|
||||
bcs SearchFound ; <'A', matched
|
||||
cmp r0,#ASC"Z"+1
|
||||
bcc SearchFound ; >'Z', matched
|
||||
; copy source to dest
|
||||
|
||||
; r4=>dest
|
||||
; r5=>last source char+1
|
||||
; r1=>first source char
|
||||
.SearchAlpha
|
||||
movb (r1)+,(r4)+
|
||||
cmp r1,r5
|
||||
bne SearchAlpha
|
||||
dec r4
|
||||
movb (r4),r0 ; is this needed?
|
||||
dec r5
|
||||
mov r2,r1
|
||||
clc
|
||||
rts pc
|
||||
|
||||
;.SearchFound
|
||||
;dec r5 ; Point to last character of source
|
||||
;movb (r3),r1 ; Get new token flag
|
||||
;dec r3 ; Point to token byte
|
||||
;movb (r3),r0 ; Get token byte
|
||||
;sec
|
||||
;rts pc
|
||||
; R0=token, R1=new flag, R5=last matched char
|
||||
; flags=CS
|
||||
|
||||
; Print character or token
|
||||
; ========================
|
||||
; On entry, r0=character
|
||||
; On exit, r0,r2 corrupted
|
||||
;
|
||||
.PrintR0TokenChar
|
||||
tstb r3 ; Within a string?
|
||||
bne PrintAscii ; Print via OSASCI
|
||||
.PrintR0Token
|
||||
tstb r0 ; Is it a token?
|
||||
bpl PrintAscii ; No, print via OSASCI
|
||||
mov r1,-(sp)
|
||||
adr TokenTable,r2
|
||||
.DetokeniseLp1
|
||||
mov r2,r1 ; Save start of this token string
|
||||
.DetokeniseLp2
|
||||
tstb (r2)+ ; Loop to find b7=1
|
||||
bpl DetokeniseLp2
|
||||
inc r2 ; Step past tokeniser flags
|
||||
cmpb r0,-2(r2)
|
||||
bne DetokeniseLp1 ; No match, loop back
|
||||
.DetokeniseLp3
|
||||
movb (r1)+,r0
|
||||
bmi DetokeniseDone ; Exit if b7 set
|
||||
jsr pc,PrintR0 ; Print character
|
||||
br DetokeniseLp3
|
||||
.DetokeniseDone
|
||||
mov (sp)+,r1
|
||||
rts pc
|
||||
|
||||
; Read line number
|
||||
; ================
|
||||
; On entry, r5=>start of number
|
||||
;
|
||||
.ReadLineNumber ; r5=>may be leading spaces
|
||||
jsr pc,SkipSpaceThis
|
||||
;
|
||||
.ReadLineNumberHere
|
||||
; On entry, r5=>start of number
|
||||
; r0= first character, not yet checked
|
||||
; On exit, CS: not a line number
|
||||
; r5=>unchanged, first character, not a digit
|
||||
; r0= character at (R5)
|
||||
; CC: a line number
|
||||
; r4=line number
|
||||
; r5=>first non-digit character
|
||||
; r0= character at (R5)
|
||||
jsr pc,CheckDigit
|
||||
bcs ReadLineNotNum2 ; Not a decimal number
|
||||
mov r5,-(sp) ; Save line pointer
|
||||
jsr pc,EvalDecimalInt ; Read integer number to R3/R4, r5=>non-digit, r0=(R5)
|
||||
tst r3
|
||||
sec
|
||||
bne ReadLineNotNum1 ; Number>65535
|
||||
cmp #&FF00,r4 ; SC if number>&FF00
|
||||
bcs ReadLineNotNum1
|
||||
tst (sp)+ ; Drop saved line pointer, clear Carry
|
||||
rts pc ; CC=valid line number
|
||||
.ReadLineNotNum1
|
||||
mov (sp)+,r5 ; Restore line pointer
|
||||
movb (r5),r0 ; R0=character at (R5)
|
||||
.ReadLineNotNum2
|
||||
rts pc ; CS=invalid line number
|
||||
|
||||
; Find line in program
|
||||
; ====================
|
||||
; On entry, r4=line number
|
||||
; On exit, r1=><cr> just before line to execute, to pass to r5
|
||||
; CC+EQ, line found
|
||||
; CC+NE, line not found
|
||||
; MI+CS+NE, end of program
|
||||
; Corrupts r0, r2
|
||||
;
|
||||
.LineFind
|
||||
mov SV_PAGE,r1
|
||||
.LineFindLp
|
||||
movb 1(r1),r0 ; Get line number high
|
||||
cmpb r0,#&FF
|
||||
beq LineFindEnd ; End of program
|
||||
movb 2(r1),r2 ; Get line number low
|
||||
swab r0
|
||||
bic #&00FF,r0
|
||||
bic #&FF00,r2
|
||||
bis r2,r0 ; r0=line number
|
||||
cmp r0,r4 ; Got to matching or higher line number?
|
||||
bcc LineFindFound ; r1=><cr> before matching line
|
||||
movb 3(r1),r0
|
||||
bic #&FF00,r0
|
||||
add r0,r1 ; Step to next line
|
||||
br LineFindLp
|
||||
.LineFindEnd
|
||||
tst r0 ; NE
|
||||
sec
|
||||
.LineFindFound
|
||||
; If line found, CC+EQ, r1=><cr> before matching line
|
||||
; If line not found, CC+NE, r1=><cr> before next line
|
||||
; If end of program, MI+CS+NE, r1=><cr> before &FF end marker
|
||||
rts pc
|
||||
|
||||
; TokenFind - Look for a line starting with a token
|
||||
; =================================================
|
||||
; On entry, r0= token to look for, eg DEF, DATA
|
||||
; r1=>current search point
|
||||
; On exit, r1=>after matching token
|
||||
; CC= Line not found
|
||||
; CS= Line found
|
||||
.TokenFindLp1
|
||||
dec r1 ; Step back to current character
|
||||
.TokenFind
|
||||
cmpb (r1)+,#13 ; Skip until <cr>
|
||||
bne TokenFind
|
||||
cmpb (r1)+,#&FF
|
||||
beq TokenFindEnd ; CC=End of program
|
||||
inc r1 ; Step past <linelo>
|
||||
.TokenFindLp2
|
||||
inc r1 ; Step past <len>
|
||||
cmpb (r1),#ASC" "
|
||||
beq TokenFindLp2 ; Skip any leading spaces
|
||||
cmpb (r1)+,r0 ; Check if matching token
|
||||
bne TokenFindLp1 ; No match, skip this line
|
||||
sec ; CS=Line found
|
||||
.TokenFindEnd
|
||||
rts pc
|
||||
|
||||
Reference in New Issue
Block a user