Original import of base code

This commit is contained in:
2026-05-12 14:27:05 +01:00
parent 87cdfeaf9a
commit 70995430ac
60 changed files with 15628 additions and 0 deletions
+743
View File
@@ -0,0 +1,743 @@
; > Variables
; Handle BASIC variables
; 24-Feb-2009: Static integer variables and indirection
; 25-Feb-2009: Reading $<addr> and $$<addr>
; 15-May-2010: VarFind returns combined type/size in r3, <base><ind><off> works
; 31-Jan-2012: Finds and creates dynamic variables, all heap items now word aligned
; cmdCLEAR now here, VarFind now never returns "invalid name", always gives an error
; 23-Nov-2012: address|offset allowed
; 09-Dec-2013: FindSubroutine moved to here so callable by AddrOf, VarFind tweeked to not
; store terminating bracket with PROCname(, FNname(
; 02-Feb-2014: Array variables returned
; 31-Aug-2015: fnREPORT moved here to return via FindStringVal
; CLEAR - Clear heap
; ==================
; LOMEM=TOP
; VAREND=TOP
; DATAPTR=PAGE
; STACK=HIMEM
; Clear dynamic variables
.cmdCLEAR ; Fall through
.VarsHeapInit
mov SV_PAGE,SV_DATA ; DATAPTR=PAGE, start of program
mov (sp),r1 ; Get return address
mov SV_HIMEM,sp ; Clear BASIC stack
clr -(sp) ; Put zero at top of stack
mov sp,SV_STACK ; Clear error stack
mov r1,-(sp) ; Stack return address
mov SV_TOP,r4 ; r4=TOP
br VarsClear
; LOMEM= - Set heap start, clearing heap
; ======================================
; Check for '=', evaluate integer
; Set LOMEM
; Set VAREND=LOMEM
; Clear dynamic variables
.cmdLOMEM
jsr pc,EvalEqual ; Check for '=', get integer
.VarsClear
inc r4 ; Pad upwards, if LOMEM=TOP and TOP is odd
bic #1,r4 ; Ensure word aligned
mov r4,SV_LOMEM ; Set new LOMEM, start of heap
mov r4,SV_VAREND ; Set new VAREND, end of heap
adr SV_VARPTR,r1 ; Point to variables pointers
mov #(SV_ENDPTR-SV_VARPTR)/2,r0 ; Number of pointers
.VarsClearLp
clr (r1)+ ; Clear this pointer
dec r0
bne VarsClearLp ; Loop for all pointers
.VarFindExit1
rts pc
; VarFindCreateAddress
; ====================
; Called from AddrOf function
; r0= first character
; r5=>first character
;
.VarFindCreateAddress
tstb r0
bpl VarFindCreate ; Not FN/PROC, scan for variable
; VarFindSubroutine - Find a FN/PROC in the heap, or in the program
; =================================================================
; On entry, r0= FN/PROC token
; r5=>FN/PROC at start of name
; On exit, Error if doesn't exist
; r5=>after end of variable name
; r4=address of data block
; r3/r2/r1/r0=corrupted
;
.VarFindSubroutine
inc r5 ; r5=>FN/PROC name
; FindSubroutine - called here from FN/PROC dispatch
; --------------------------------------------------
; On entry, r0= FN/PROC token
; r5=>first character of name
;
.FindSubroutine
mov r0,-(sp) ; Save FN/PROC token
jsr pc,VarFindPROC ; Look for FN/PROC in heap
bne FindSubFound ; In heap, jump to call it
; Look for DEFPROC/DEFFN in program
; r4=>heap pointer to add to
; r5=>1st char of name
;
mov SV_PAGE,r1
.FindSubSearch
mov #tknDEF,r0
jsr pc,TokenFind ; Look for a line starting with DEF
bcc errNoSuchPROC ; End of program with no match found
.FindSubSpace
movb (r1)+,r0
cmpb r0,#ASC" "
beq FindSubSpace ; Skip spaces after DEF
cmpb r0,(sp) ; Is it a FN/PROC
bne FindSubSearch ; No, keep looking
; We've now found a DEFPROC or a DEFFN
; r5=>start of FN/PROC name in call
; r4=>heap pointer to add to
; r1=>start of FN/PROC name in definition
mov r5,r3
mov r1,r2
.FindSubLp
movb (r1)+,r0 ; Get character from definition name
jsr pc,VarChkChar ; End of definition name?
bcs FindSubMatch ; Yes, check for end of calling name
cmpb r0,(r3)+ ; Does it match call name?
beq FindSubLp ; Yes, loop to check more characters
bne FindSubSearch ; No match, look for another DEF
.FindSubMatch
movb (r3)+,r0 ; Get character from call name
jsr pc,VarChkChar ; End of name calling name?
bcc FindSubSearch ; Not end of calling name, look for another
dec r3
dec r1
; We've now found a matching DEFPROC or a DEFFN
; r5=>start of FN/PROC name in call
; r4=>heap pointer to add to
; r3=>end of FN/PROC name in call
; r1=>end of FN/PROC name in definition
mov (sp),r2 ; r2=FN/PROC token
mov r1,-(sp) ; Save destination address
jsr pc,VarCreate ; Create entry in heap
; r0= terminating calling character
; r2= FN/PROC token
; r3= corrupted
; r4=>data block
; r5=>just after calling FN/PROC name
; (sp)= destination address
mov (sp)+,(r4) ; Store dest address in heap
.FindSubFound
mov (sp)+,r0
rts pc
.errNoSuchPROC
jsr pc,Error
equb 29,"No such ",tknFN,"/",tknPROC,0
align
; VarFindCreate - Find a variable, and create it if non-existant
; ==============================================================
; On entry, r5=>first character of name
; On exit, CS=bad variable name - error generated
; CC=valid variable name
; NE=variable found
; r5=>after end of variable name
; r4=address of data block
; r3=size/type of variable
; 0001 - byte
; 0004 - integer
; 0005 - real
; 8000 - dynamic string
; 8100 - $string
; 8200 - $$string
; 4xxx - array of number
; Cxxx - array of string
; r2/r1/r0=corrupted
;
.VarFindCreate
jsr pc,SkipSpaceThis
.VarFindCreate1
jsr pc,VarFindExist ; Look for variable
bne VarFindExit1 ; NE - Variable found
clr r2 ; r2=0 - not FN/PROC
; Valid variable name, but doesn't exist
; r4=>last link, aligned
; r5=>second character of variable name
; r2=0 - not FN/PROC or array - don't create entry ending with '('
; r2<>0 - FN/PROC or array - ok to create entry ending with '('
; r2<&80 - array - include '(' in entry name
; r2>&7F - FN/PROC - don't include '(' in entry name
; Variable info block layout:
; <link><name><00><aa><bb><cc><dd><ee>
; <link><name>%<00><aa><bb><cc><dd>
; <link><name>$<00><ll><hh><len><max>
; <link><name>(<00><ll><hh>
; <link><name>%(<00><ll><hh>
; <link><name>$(<00><ll><hh>
; <link><procname><00><ll><hh>
; <link><fnname><00><ll><hh>
.VarCreate
mov r5,-(sp) ; Save pointer to variable name
mov #16+256,r1 ; Size of info block plus some overhead
.VarCreateLp1
inc r1 ; Count length of variable name
movb (r5)+,r0 ; Get variable name character
jsr pc,VarChkChar
bcc VarCreateLp1 ; Loop for valid characters
;This is wrong place for this test
;tst r2
;bne VarCreate0 ; PROC/FN, terminating '(' allowed
;cmpb r0,#ASC"("
;bne VarCreate0
;jmp errArray ; Arrays must already exist
;.VarCreate0
mov SV_VAREND,r0 ; End of heap, will be aligned if not manually messed with
add r0,r1 ; Add length of variable name and info block
cmp r1,sp ; Would this overlap stack?
bcs VarCreate1
jmp errNoRoom
.VarCreate1
mov (sp)+,r5 ; Get pointer to variable name
mov r0,(r4) ; Point current link to new info block at VAREND
mov r0,r4 ; r4=>new variable info block
clr (r4)+ ; Set next link to zero
.VarCreateLp2
movb (r5)+,r0 ; Get variable name character
movb r0,(r4)+ ; Store in info block
jsr pc,VarChkChar
bcc VarCreateLp2 ; Loop to end of variable name
;
; r5=v
; a
; a(
; a%
; a$
; a%(
; a$(
; ab
; ab%
; ab$
; ab(
; ab%(
; ab$(
mov #&4000,r3 ; r3=&4000 - FN/PROC
tstb r2
bmi VarCreatePROC ; FN/PROC, don't add '(' to name
;mov #&8000,r3 ; r3=&8000 - dynamic string
asl r3 ; r3=&8000 - dynamic string
cmpb r0,#ASC"$"
beq VarCreateIntStr
mov #&0004,r3 ; r3=&0004 - integer
cmpb r0,#ASC"%"
beq VarCreateIntStr
inc r3 ; r3=&0005 - real
cmpb r0,#ASC"("
beq VarCreateArray ; Array or PROC(/FN(
.VarCreatePROC
dec r5 ; Point program back to terminating character
dec r4 ; Step back to terminator
br VarCreateInfo
.VarCreateIntStr
movb (r5),r0
cmpb r0,#ASC"("
bne VarCreateInfo
inc r5 ; Step past '('
movb r0,(r4)+ ; Store '(' in info block
.VarCreateArray
bis #&4000,r3 ; Array
.VarCreateInfo
clrb (r4)+ ; Store terminator
clrb (r4)+ ; Pad to align
bic #1,r4 ; Ensure aligned
mov r4,r1 ; r4=>data block
clr (r1)+ ; Clear first two bytes for array
bit #&4000,r3
bne VarCreateDone ; Array
clr (r1)+ ; Clear two more bytes for String or Integer
bit #&0001,r3
beq VarCreateDone ; Not real
clr (r1)+ ; Clear two more bytes for real
.VarCreateDone
mov r1,SV_VAREND ; Update end of heap
rts pc ; r4=>data block
; r3= data type/size
; VarFindExist - Find an existing variable
; ========================================
; On entry, r5=>first character of name
; On exit, CS=bad variable name - error generated
; r5=preserved
; CC=valid variable name
; EQ=variable not found
; r5=>first character of variable name
; r4=address of previous linked list
; NE=variable found
; r5=>after end of variable name
; r4=address of data block
; r3=size/type of variable
; 0001 - byte
; 0004 - integer
; 0005 - real
; 8000 - dynamic string
; 8100 - $string
; 8200 - $$string
; 4xxx - array of number
; Cxxx - array of string
; r2/r1/r0=corrupted
;
.VarFindExist
movb (r5),r0 ; Get first character
clr r4 ; Zero base for !x, ?x, |x
cmpb r0,#ASC"!"
beq VarFindIndirect ; Evaluate !x as 0!x
cmpb r0,#ASC"?"
beq VarFindIndirect ; Evaluate ?x as 0?x
cmpb r0,#ASC"|"
beq VarFindIndirect ; Evaluate |x as 0|x
cmpb r0,#ASC"$"
beq VarFindChkDol ; Evaluate $<addr> and $$<addr>
cmpb r0,#ASC"@"
bcs VarBadName ; Bad variable name, r5 preserved
; VarFindVariable - Find a variable ignoring indirections
; -------------------------------------------------------
.VarFindVariable
movb (r5)+,r0 ; Get first character
cmp r0,#ASC"["
bcc VarFindDyn ; --> needs to call, then check for |?!
cmpb (r5),#ASC"%" ; Is it <uc>% ?
bne VarFindDyn ; No, look for dynamic variable --> indir
cmpb 1(r5),#ASC"(" ; Is it <uc>%( ?
beq VarFindDyn ; Yes, look for dynamic array entry --> indir
inc r5 ; Step past <uc>%
add r0,r0
add r0,r0 ; r0=ASC"<uc>"*4
adr SV_VARS-4*ASC"@",r4
add r0,r4 ; r4=><data block>
mov #4,r3 ; r3=&0004, integer - number, four bytes
.VarFindCheckIndir
movb (r5),r0
cmpb r0,#ASC"!" ; Is it var!offset ?
beq VarFindIndir
cmpb r0,#ASC"?" ; Is it var?offset ?
beq VarFindIndir
cmpb r0,#ASC"|" ; Is it var|offset ?
;;clc
bne VarFindExit ; NE=found
mov r5,r1 ; Save program pointer in R1
inc r5 ; Step past |
jsr pc,CheckEndStatement
bne VarFindIndirReal ; Not expression|
mov r1,r5 ; Restore program pointer, also NE=found
;;clc ; CC=ok, NE=found
;;.VarBadName
.VarFindExit
rts pc
.VarBadName
jmp errSyntax
;
.VarFindIndirReal
movb #ASC"|",r0 ; Restore r0="|"
mov r1,r5 ; Point back to indir operator
.VarFindIndir ; A%?num or A%!num
mov r0,-(sp) ; Stack indirection operator
jsr pc,VarFindValNum ; Get value of <uc>% to r4
br VarFindInd2
.VarFindChkDol
cmpb 1(r5),#ASC"$" ; Is it $$<addr> ?
bne VarFindIndirect ; No, jump for $<addr>
inc r5 ; Step past first '$'
inc r0 ; Make operator '%'
.VarFindIndirect
mov r0,-(sp) ; Stack indirection operator
.VarFindInd2
mov r4,-(sp) ; Stack base address
inc r5 ; Step past indirection operator
jsr pc,EvalIntVal ; Evaluate following numeric
add (sp)+,r4 ; Add stacked base to numeric
mov (sp)+,r3 ; Get indirection operator back
cmpb r3,#ASC"!"
beq VarFindPling ; Return with size=4
cmpb r3,#ASC"$"
beq VarFindDollar ; Return fixed cr-string
cmpb r3,#ASC"%"
beq VarFindDouble ; Return fixed null-string
cmpb r3,#ASC"?"
beq VarFindQuery ; CC=ok, return with size=1
mov #5,r3 ; |offset, float - number, five bytes
;;clc ; CC=ok, NE=found (clc not needed)
rts pc
.VarFindPling
mov #4,r3 ; name?offset - four bytes, sets NE=found
rts pc
.VarFindQuery
mov #1,r3 ; name?offset - single byte, sets NE=found
rts pc
.VarFindDollar
mov #&8100,r3 ; type=cr-string, sets NE=found
rts pc
.VarFindDouble
mov #&8200,r3 ; type=null-string, sets NE=found
rts pc
; Look for a FN/PROC in the heap
; ------------------------------
; On entry, r0= first character of name, FN/PROC
; r5=>second character
;
.VarFindPROC
mov #SV_PROCPTR-SV_VARPTR,r1
cmpb r0,#tknPROC
beq VarFindDyn1 ; Look through PROC list
mov #SV_FNPTR-SV_VARPTR,r1
br VarFindDyn1 ; Look through FN list
; Look for a variable in the heap
; -------------------------------
; On entry, r0= first character of variable
; r5=>second character
;
.VarFindDyn
jsr pc,VarChkLetter
bcs VarBadName ; Starts with invalid character
add r0,r0 ; r0=initial letter * 2
.VarFindDyn1
adr SV_VARPTR-2*ASC"A",r4
add r0,r4 ; r4=pointer to linked list
;
.VarFindNext
;;clc
mov (r4),r0 ; Get pointer to next item
beq VarFindExit ; End of linked list, exit with EQ, r4=>pointer, r5=>2nd char of name
mov r0,r4 ; r4=>current information block
mov r5,r3 ; r3=>second character of variable name
mov r4,r2
add #2,r2 ; r2=>start of stored variable name
.VarFindLp
movb (r2)+,r0 ; Get character from stored variable name
cmpb r0,(r3)+ ; Does it match program variable name
beq VarFindLp ; Yes, loop to check more characters
tst r0 ; End of stored variable name?
bne VarFindNext ; No, look for another name
;
dec r3 ; Point back to nonmatching character
dec r3 ; Point back to last matching character
movb (r3),r1 ; Get last matching character
cmpb r1,#ASC"("
beq VarFindArray ; It's an array
inc r3
movb (r3),r0 ; Get nonmatching character
jsr pc,VarChkType ; Check if valid variable name or suffix character
bcs VarFindArray ; No more characters, check for array
tstb -1(r5) ; Check first character of name
bpl VarFindNext ; Not a FN/PROC, look for another name
jsr pc,VarChkChar ; Test for middle character
bcc VarFindNext ; More characters in FN/PROC name, look for another name
br VarProcFound ; FN/PROC name found
.VarFindArray
dec r3 ; Step back to type character
movb (r3)+,r0 ; Get type character, step past character
inc r3 ; Step past '('
sbc r3 ; Step back if not '('
.VarProcFound
mov r3,r5 ; r5=>character after end of name
mov r2,r4 ; r4=>variable data block
inc r4
bic #1,r4 ; Align data block
mov #&8000,r3 ; Type=string
cmpb r0,#ASC"$"
beq VarFound
mov #&0004,r3 ; Type=integer
cmpb r0,#ASC"%"
beq VarFound
inc r3 ; Type=real
.VarFound
cmpb r1,#ASC"("
beq VarArrayFound ; Check for array references
tst r3 ; NE=found, MI=string, PL=number
bmi VarFindExit3 ; Exit with string
jmp VarFindCheckIndir ; Number - test for indirection
; matching variable name found
; name<00>
; name%<00>
; name$<00>
.VarArrayFound
cmpb (r5),#ASC")" ; Is it array()
bne VarArrayIndex
inc r5 ; Step past ')'
bis #&4000,r3 ; NE=found, &40=array, MI=string, PL=number
.VarFindExit3
;;clc ; CC=ok
rts pc
; name(<00>
; name%(<00>
; name$(<00>
.VarArrayIndex
; r5=>m,n,o,p)
; r4=>pointer to array info
;mov (r4),r4 ; r4=>array info
;beq errArray ; Array undefined
;
; r4=>dims, dim1, dim2, dim3, dim4
; r3=object type &8000, &0005, &0004
;
mov r3,-(sp) ; Save object type
mov (r4)+,-(sp) ; Save number of dimensions
clr -(sp) ; Save initial index into array
mov r4,-(sp) ; Save address of dimensions list
br VarArrayParse
.VarArrayLp
cmpb (r5)+,#ASC","
bne errBadSubscript
mov r3,-(sp) ; Stack current index
mov r1,-(sp) ; Stack pointer to current dimension
.VarArrayParse
jsr pc,EvalInteger ; Evaluate dimension
tst r3
bne errBadSubscript ; sub>65535 - too big
mov (sp)+,r1 ; r1=>current dimension
mov (r1)+,r3 ; r3= current dimension
inc r3 ; Add one to get dimension size
cmp r4,r3 ; Is subscript larger than dimension?
bcc errBadSubscript
mov (sp)+,r2 ; r2=current index
;
; sp=>num, type
; r4=subscript
; r3=current dimension max
; r2=current index
; r1=>next dimension
;
#ifndef NOMUL
mul r2,r3 ; r3=r2*r3 - offset=offset*size
#else
jsr pc,R2timesR3toR3 ; r3=r2*r3 - offset=offset*size
#endif
add r4,r3 ; offset=offset*size+subscript
dec (sp) ; Decrement number of dimensions
bne VarArrayLp ; Parse next subscript
jsr pc,CheckClose
tst (sp)+ ; Pop num
;
mov (sp)+,r2 ; Get object type
mov r3,r4
asl r4
asl r4 ; r4=index*4
bit r2,#1
beq VarArrayAdd
add r3,r4 ; r4=index*5
.VarArrayAdd
add r1,r4 ; r4=>data item
mov r2,r3 ; r3=object size, NE=variable found
rts pc
.errArray
jsr pc,Error
equb 14,"Array",0
align
.errBadSubscript
jsr pc,Error
equb 15,"Subscript",0
align
; VarFindVal - Find a variable and return its value
; =================================================
; On entry, r5=>first character of name
; On exit, r4/r3/r2=value
; r1/r0=corrupted
;
.VarFindVal
jsr pc,VarFindExist ; Find existing variable
;;bcs jmpNoSuchVar ; Bad variable name
; test here for OPT 2 in assembler
beq errNoSuchVar ; Variable not found
.VarFindValFetch
bit #&4000,r3
bne errArray ; Can't do =array() like this
tst r3 ; r3=1/4/5 int/byte/float, r3=8xxx string
bmi VarFindString ; If string, pointing to string descriptor
.VarFindValNum
clr r2 ; Prepare for integer
movb (r4)+,r0 ; Get first byte
bic #&FF00,r0
dec r3
beq VarFindByte ; Single byte
movb (r4)+,r1 ; Get second byte
bic #&FF00,r1
swab r1
bis r1,r0 ; r0=1st/2nd bytes
movb (r4)+,r1 ; Get third byte
movb (r4)+,r2 ; Get fourth byte
bic #&FF00,r1
bic #&FF00,r2
swab r2
bis r2,r1 ; r1=3rd/4th bytes
clr r2 ; Prepare for word
cmp r3,#3
beq VarFindWord
movb (r4),r2 ; Get fifth byte for float
bic #&FF00,r2
.VarFindWord
mov r1,r3
.VarFindByte
mov r0,r4
;;clc
tst r2
rts pc
.fnREPORT
cmpb (r5)+,#ASC"$" ; Check for '$'
bne errNoSuchVar
mov SV_FAULT,r4
inc r4 ; r4=>error string
mov #&8200,r3 ; r3=null-string
; Fall through to find length of null-string
; VarFindString - convert string description into full string
; -----------------------------------------------------------
; If a string found, registers will hold:
; r3=&8000, r4=>aligned string descriptor block = addr.lo, addr.hi, length, allocated
; r3=&8100, r4=>start of cr-string
; r3=&8200, r4=>start of null-string
.VarFindString
mov r3,r2 ; r2=string type
clr r3 ; Set length to zero
clr r0 ; Look for CHR$0
bit #&0200,r2 ; A null-string?
bne VarFindStrCount
mov #13,r0 ; Look for CHR$13
bit #&0100,r2 ; A cr-string?
bne VarFindStrCount
movb 2(r4),r3 ; Get string length
bic #&FF00,r3 ; 8-bit length
mov (r4),r4 ; Get string start address
clc ; CLC=OK
tst r2 ; Set flags from string type, also clears Carry
rts pc
.VarFindStrCount
mov r4,r1 ; Copy start address to r1
.VarFindStrLp
inc r3 ; Increment length
cmp r3,#256 ; String too long?
bcc VarFindStrZero ; No terminator, return null
cmpb (r1)+,r0 ; Terminator found?
bne VarFindStrLp ; No, loop until found or too long
dec r3 ; Remove terminator from count
clc ; CLC=OK
tst r2 ; Set flags from string type, also clears Carry
rts pc
.VarFindStrZero
clr r3 ; Return zero-length string
;;clc ; CLC=OK
tst r2 ; Set flags from string type, also clears Carry
rts pc
.errNoSuchVar
jsr pc,Error
equb 26,"No such variable",0
align
; Array function
; ==============
; =DIM(array()) - returns number of dimensions
; =DIM(array(),n) - return size of dimension n
;
#ifndef NOEXTRAFN
.fnDIM
cmpb (r5)+,#ASC"(" ; Check for opening bracket
bne errArray
jsr pc,VarFindExist ; Look up array
beq errNoSuchVar ; Array doesn't exist
bit #&4000,r3
beq errArray ; Not an array variable
;mov (r4),r4 ; Get start of array data
;beq errArray ; Array Undimensioned
jsr pc,SkipSpaceThis
cmpb r0,#ASC","
bne fnDIM2 ; Jump with DIM(array()) to return number of dimensions
; =DIM(array(),n)
; ---------------
mov r4,-(sp) ; Save address of array info
jsr pc,EvalComma
tst r3
bne errBadSubscript ; =DIM(array(),>65535)
tst r4
beq errBadSubscript ; =DIM(array(),0)
mov (sp)+,r3 ; r3=>array info
cmp (r3),r4
bcs errBadSubscript ; =DIM(array(),n) where n is too large
add r4,r4 ; Double r4
add r3,r4 ; Add to base of array info
.fnDIM2
jsr pc,CheckClose
;.fnDIM3
mov (r4),r4 ; Get number of dimensions or dimension size
clr r3
clr r2
;.fnDIMexit
rts pc
#endif
; Check if char is valid for a variable name
; ------------------------------------------
; CS - invalid variable name character
; CC - valid variable name character
; CC EQ - valid terminating character $ % (
;
.VarChkType ; Test for any character
cmpb r0,#ASC"("
beq VarChkCharOk ; '(' - exit with CC, EQ
cmpb r0,#ASC"$"
beq VarChkCharOk ; '$' - exit with CC, EQ
cmpb r0,#ASC"%"
beq VarChkCharOk ; '%' - exit with CC, EQ
;
.VarChkChar ; Test for middle character
cmpb r0,#ASC"0"
bcs VarChkCharOk ; <'0' - exit with CS
cmpb #ASC"9",r0
bcc VarChkCharCC ; '0'-'9' - exit with CC, NE
;
.VarChkLetter ; Test for starting character
cmpb r0,#ASC"A"
bcs VarChkCharOk ; ':'-'@' - exit with CS
cmpb #ASC"Z",r0
bcc VarChkCharCC ; 'A'-'[' - exit with CC, NE
cmpb r0,#ASC"_"
bcs VarChkCharOk ; '['-'^' - exit with CS
cmpb #ASC"z",r0
bcs VarChkCharOk ; >'z' - exit with CS
; '_'-'z' - exit with CC, NE
.VarChkCharCC
tst r0 ; NE, also clears carry
clc ; CC
.VarChkCharOk
rts pc