mirror of
https://github.com/Tolik-Trek/Estex-DSS.git
synced 2026-06-15 09:21:47 +03:00
276 lines
6.5 KiB
NASM
276 lines
6.5 KiB
NASM
;///////////////////////////////////////////////////
|
|
;
|
|
; GOTO / GOSUB / RETURN. Jumps inside a BAT-file by
|
|
; ":label", MS-DOS / 4DOS style.
|
|
;
|
|
; GOTO label - jump to ":label"
|
|
; GOSUB label - call subroutine at ":label"
|
|
; RETURN - return to the line after the GOSUB
|
|
;
|
|
;///////////////////////////////////////////////////
|
|
|
|
GOTO_LABEL_MAX EQU 15 ; max label name length
|
|
GOSUB_MAX EQU 16 ; max GOSUB nesting depth
|
|
|
|
;-------------------------------------------------
|
|
; GOTO label
|
|
; in: de -> argument string (label, may start with ':')
|
|
;-------------------------------------------------
|
|
cmd_goto:
|
|
ex de,hl ; hl -> argument text
|
|
call GOTO_PARSE ; -> goto_label (upper, 0-term)
|
|
ld a,(goto_label)
|
|
or a
|
|
jp z,.empty ; no label name
|
|
jp GOTO_START ; rewind + start the label search
|
|
.empty: ld de,MAIN_MSG.LABEL_NOT_FOUND
|
|
jp gAbort
|
|
|
|
;-------------------------------------------------
|
|
; GOSUB label
|
|
; in: de -> argument string (label, may start with ':')
|
|
;-------------------------------------------------
|
|
cmd_gosub:
|
|
ex de,hl ; hl -> argument text
|
|
call GOTO_PARSE ; -> goto_label (saved in memory)
|
|
ld a,(goto_label)
|
|
or a
|
|
jp z,cmd_goto.empty
|
|
call GOSUB_PUSH ; remember the return position
|
|
jp GOTO_START ; then jump like GOTO
|
|
|
|
;-------------------------------------------------
|
|
; RETURN - resume after the matching GOSUB
|
|
;-------------------------------------------------
|
|
cmd_return:
|
|
ld a,(gosub_sp)
|
|
or a
|
|
jr z,.empty ; RETURN without GOSUB
|
|
dec a
|
|
ld (gosub_sp),a
|
|
add a,a
|
|
add a,a ; a = sp*4 (byte offset in stack)
|
|
ld e,a
|
|
ld d,0
|
|
ld hl,gosub_stk
|
|
add hl,de
|
|
ld e,(hl) ; saved offset (low word)
|
|
inc hl
|
|
ld d,(hl)
|
|
inc hl
|
|
ld (gosub_lo),de
|
|
ld e,(hl) ; saved offset (high word)
|
|
inc hl
|
|
ld d,(hl)
|
|
ld (gosub_hi),de
|
|
ld a,(BAT_FM) ; bat-file handle
|
|
ld hl,(gosub_hi) ; HL = offset high 16 bits
|
|
ld ix,(gosub_lo) ; IX = offset low 16 bits
|
|
ld bc,Dss.Move_FP.FrStart ; B=0 (from start), C=#15
|
|
RST ToDSS
|
|
jr c,.io
|
|
xor a
|
|
ld (MOVWORD.count),a ; force re-read from saved position
|
|
ret ; back to NEWLINE -> line after GOSUB
|
|
.empty: ld de,MAIN_MSG.RET_NO_GOSUB
|
|
jp gAbort
|
|
.io: call print_err_message
|
|
jp gAbort.silent
|
|
|
|
;-------------------------------------------------
|
|
; Parse a label argument into goto_label
|
|
; in: hl -> text (optional spaces/TAB, optional ':')
|
|
; out: goto_label = upper-cased, 0-terminated token
|
|
;-------------------------------------------------
|
|
GOTO_PARSE:
|
|
.sp0: ld a,(hl) ; skip leading blanks (space / TAB)
|
|
cp " "
|
|
jr z,.sp0i
|
|
cp "\t"
|
|
jr nz,.nosp0
|
|
.sp0i: inc hl
|
|
jr .sp0
|
|
.nosp0: cp ":" ; allow "GOTO :label"
|
|
jr nz,.sp1
|
|
inc hl
|
|
.sp1: ld a,(hl) ; skip blanks after ':'
|
|
cp " "
|
|
jr z,.sp1i
|
|
cp "\t"
|
|
jr nz,.copy
|
|
.sp1i: inc hl
|
|
jr .sp1
|
|
.copy: ld de,goto_label
|
|
ld b,GOTO_LABEL_MAX
|
|
.cloop: ld a,(hl)
|
|
cp " "+1 ; a <= ' ' -> end of token
|
|
jr c,.cend
|
|
call COMPARE.cmp_AZ ; -> upper case
|
|
ld (de),a
|
|
inc hl
|
|
inc de
|
|
djnz .cloop
|
|
.cend: xor a
|
|
ld (de),a ; 0-terminate
|
|
ret
|
|
|
|
;-------------------------------------------------
|
|
; Rewind the BAT-file and start the label search
|
|
;-------------------------------------------------
|
|
GOTO_START:
|
|
ld a,(BAT_FM) ; bat-file handle
|
|
ld hl,0 ; offset low
|
|
ld ix,0 ; offset high
|
|
ld bc,Dss.Move_FP.FrStart ; B=0 (from start), C=#15
|
|
RST ToDSS
|
|
jr c,.io
|
|
xor a
|
|
ld (MOVWORD.count),a ; invalidate NEWLINE read buffer
|
|
ld a,1
|
|
ld (goto_active),a ; activate the label search
|
|
ret
|
|
.io: call print_err_message
|
|
jp gAbort.silent
|
|
|
|
;-------------------------------------------------
|
|
; Push the return position (file offset of the line
|
|
; that follows the current GOSUB) onto the stack.
|
|
;-------------------------------------------------
|
|
GOSUB_PUSH:
|
|
ld a,(gosub_sp)
|
|
cp GOSUB_MAX
|
|
jr nc,.deep ; stack overflow
|
|
; current file pointer (tell): FrCurrent, offset 0
|
|
ld a,(BAT_FM)
|
|
ld hl,0
|
|
ld ix,0
|
|
ld bc,Dss.Move_FP.FrCurrent ; B=1, C=#15
|
|
RST ToDSS
|
|
jr c,.io
|
|
; on return: IX = pointer low 16, HL = pointer high 16
|
|
ld (gosub_hi),hl ; save high word
|
|
push ix
|
|
pop hl ; hl = pointer low 16
|
|
; offset = pointer - (bytes still unparsed in buffer1)
|
|
ld a,(MOVWORD.count)
|
|
ld e,a
|
|
ld d,0
|
|
or a ; CF=0
|
|
sbc hl,de ; hl = low - count
|
|
ld (gosub_lo),hl
|
|
jr nc,.nob
|
|
ld hl,(gosub_hi) ; borrow into high word
|
|
dec hl
|
|
ld (gosub_hi),hl
|
|
.nob:
|
|
; store at gosub_stk[gosub_sp]
|
|
ld a,(gosub_sp)
|
|
ld c,a ; c = old depth
|
|
add a,a
|
|
add a,a ; a = sp*4
|
|
ld e,a
|
|
ld d,0
|
|
ld hl,gosub_stk
|
|
add hl,de
|
|
ld de,(gosub_lo)
|
|
ld (hl),e
|
|
inc hl
|
|
ld (hl),d
|
|
inc hl
|
|
ld de,(gosub_hi)
|
|
ld (hl),e
|
|
inc hl
|
|
ld (hl),d
|
|
ld a,c
|
|
inc a
|
|
ld (gosub_sp),a ; depth++
|
|
ret
|
|
.deep: ld de,MAIN_MSG.GOSUB_DEEP
|
|
jp gAbort
|
|
.io: call print_err_message
|
|
jp gAbort.silent
|
|
|
|
;-------------------------------------------------
|
|
; Print message (de=index) and abort the BAT-file
|
|
;-------------------------------------------------
|
|
gAbort:
|
|
call ECHO_MESSAGE
|
|
.silent:
|
|
xor a
|
|
ld (goto_active),a ; don't double-print in cmd_break.exit
|
|
jp cmd_break.exit
|
|
|
|
;-------------------------------------------------
|
|
; Called from CMDMODE for every BAT-file line.
|
|
; Handles ":label" lines and the GOTO/GOSUB search.
|
|
;
|
|
; out: CF=1 - skip this line (label line, or searching)
|
|
; CF=0 - execute this line normally
|
|
;-------------------------------------------------
|
|
BAT_CHECK_LABEL:
|
|
ld hl,Buffers.input_line.Path
|
|
.sp: ld a,(hl) ; skip leading blanks (space / TAB)
|
|
cp " "
|
|
jr z,.spi
|
|
cp "\t"
|
|
jr nz,.first
|
|
.spi: inc hl
|
|
jr .sp
|
|
.first: cp ":" ; is it a label line ?
|
|
jr z,.label
|
|
; not a label line
|
|
ld a,(goto_active)
|
|
or a
|
|
ret z ; CF=0 -> run normally
|
|
scf ; searching -> skip line
|
|
ret
|
|
;
|
|
.label: ld a,(goto_active)
|
|
or a
|
|
jr nz,.match
|
|
; not searching: ":label" -> skip (no echo, no exec)
|
|
scf
|
|
ret
|
|
; searching: does this label match goto_label ?
|
|
.match: inc hl ; skip ':'
|
|
.msp: ld a,(hl) ; skip blanks after ':'
|
|
cp " "
|
|
jr z,.mspi
|
|
cp "\t"
|
|
jr nz,.mcmp
|
|
.mspi: inc hl
|
|
jr .msp
|
|
.mcmp: ld de,goto_label
|
|
.mlp: ld a,(de) ; target char (upper, 0-term)
|
|
or a
|
|
jr z,.mend ; target consumed
|
|
ld c,a
|
|
ld a,(hl)
|
|
cp " "+1 ; line token ended too early ?
|
|
jr c,.skip ; -> no match
|
|
call COMPARE.cmp_AZ
|
|
cp c
|
|
jr nz,.skip
|
|
inc hl
|
|
inc de
|
|
jr .mlp
|
|
.mend: ld a,(hl) ; target ended: line token must end here
|
|
cp " "+1 ; a <= ' ' -> full match
|
|
jr nc,.skip ; line label is longer -> no match
|
|
; match ! stop searching, skip the label line itself
|
|
xor a
|
|
ld (goto_active),a
|
|
scf
|
|
ret
|
|
;
|
|
.skip: scf ; keep searching, skip this line
|
|
ret
|
|
;
|
|
|
|
goto_active: db 0 ; 1 = searching for a label
|
|
goto_label: ds GOTO_LABEL_MAX+1,0 ; target label (upper, 0-term)
|
|
gosub_sp: db 0 ; GOSUB nesting depth
|
|
gosub_lo: dw 0 ; scratch (offset low)
|
|
gosub_hi: dw 0 ; scratch (offset high)
|
|
gosub_stk: ds GOSUB_MAX*4,0 ; return offsets (32-bit each)
|