Claude code. IF, GOTO, GOSUB/RETURN in BAT files.

This commit is contained in:
Tolik 2026-05-19 01:45:02 +10:00
parent ae08ad9c1e
commit e11d63b729
8 changed files with 650 additions and 9 deletions

View File

@ -231,9 +231,11 @@ MOVWORD:
ld b,a
.loop: ld a,(hl)
ld (de),a
cp "\t" ; TAB - in-line blank, keep it (MS-DOS bat)
jr z,.cont
cp " "
jr c,.loop_
inc hl
jr c,.loop_ ; <0x20 (CR/LF) -> end of line
.cont: inc hl
inc de
djnz .loop
scf
@ -281,6 +283,8 @@ CMDMODE:
;ld (D96A6),a ; (inline.asm)
call EVALCMD ; (batch.asm)
RET C
call BAT_CHECK_LABEL ; GOTO labels / search
RET C
;ld ix,T96AC ; ­ã¦­®?? § ª®¬¥­â à¨« (inline.asm)
;ld hl,T96AE ;;256 ¡ãä¥à (inline.asm)
ld hl,Buffers.input_line.Path
@ -366,8 +370,10 @@ CMDMODE:
;ld hl,Buffers.work.buffer+256;;
.A826C: ld a,(hl)
cp " "
jr z,.A826W
cp "\t"
jr nz,.A8276
inc hl
.A826W: inc hl
dec c
jr nz,.A826C
ret
@ -379,10 +385,17 @@ CMDMODE:
sbc hl,bc
ld a,c
ex af,af'
ld a," "
cpir
jr nz,.A8286
inc c
.A827S: ld a,c
or a
jr z,.A8286 ; no blank -> whole line is the command
ld a,(hl)
cp " "
jr z,.A8286
cp "\t"
jr z,.A8286
inc hl
dec c
jr .A827S
.A8286: ex af,af'
sub c
ld c,a ; ¤«¨­  á«®¢  ¨«¨ áâப¨ ?
@ -510,6 +523,10 @@ EVALSTR: ld a,(hl)
BATLIST: DZ 'PAUSE' : DW cmd_pause
DZ 'REM' : DW cmd_rem
DZ 'EXIT' : DW cmd_break
DZ 'GOTO' : DW cmd_goto
DZ 'GOSUB' : DW cmd_gosub
DZ 'RETURN' : DW cmd_return
DZ 'IF' : DW cmd_if
;
; DSS-ª®¬ ­¤ë
CMDLIST: DZ 'CD' : DW cmd_chdir

91
SHELL/Changes.txt Normal file
View File

@ -0,0 +1,91 @@
—⮠ᤥ« ­®:
1. ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
GOTO ¤«ï BAT
<EFBFBD>®¢ë© ä ©« SHELL/Commands/GOTO.ASM ? ᮤ¥à¦¨â:
cmd_goto ? ®¡à ¡®â稪 ª®¬ ­¤ë: à §¡¨à ¥â ¨¬ï ¬¥âª¨ (á ¯®¤¤¥à¦ª®© GOTO :label ¨ GOTO label, ¡¥§ ãçñâ  à¥£¨áâà ),
¯¥à¥¬ â뢠¥â BAT-ä ©« ¢ ­ ç «® (Dss.Move_FP, B=0), á¡à á뢠¥â ¡ãä¥à ç⥭¨ï (MOVWORD.count=0) ¨ ¢ª«îç ¥â ०¨¬ ¯®¨áª  ¬¥âª¨.
BAT_CHECK_LABEL ? ¢ë§ë¢ ¥âáï ¤«ï ª ¦¤®© áâப¨ BAT-ä ©« : ¯à®¯ã᪠¥â áâப¨-¬¥âª¨ :label (¡¥§ íå  ¨ ¢ë¯®«­¥­¨ï, ª ª ¢ MS-DOS)
¨ ¢ ०¨¬¥ ¯®¨áª  ¯à®¯ã᪠¥â ¢á¥ áâப¨, ¯®ª  ­¥ ­ ©¤ñ⠭㦭ãî ¬¥âªã.
ˆ§¬¥­ñ­­ë¥ ä ©«ë (¯à ¢ª¨ ¢­¥á¥­ë ¯®¡ ©â®¢®, ª®¤¨à®¢ª  CP866 ¨ ¯¥à¥­®áë áâப á®åà ­¥­ë):
SHELL/SHELL.ASM ? include 'Commands/goto.asm'
SHELL/BATCH.ASM ? DZ 'GOTO' : DW cmd_goto ¢ BATLIST (ª®¬ ­¤  ⮫쪮 ¤«ï BAT, ª ª PAUSE/REM); ¢ë§®¢ BAT_CHECK_LABEL ¢ CMDMODE áà §ã ¯®á«¥ EVALCMD
SHELL/Commands/BREAK.ASM ? ¯à¨ § ¢¥à襭¨¨ BAT, ¥á«¨ ¯®¨áª ¬¥âª¨ ­¥ § ¢¥à訫áï, ¯¥ç â ¥â ?Label not found? ¨ ¯à¥à뢠¥â ¢ë¯®«­¥­¨¥ (¯®¢¥¤¥­¨¥ MS-DOS)
SHELL/Messages/main_txt.asm ? ¤®¡ ¢«¥­® á®®¡é¥­¨¥ Label not found ¨  «¨ á MAIN_MSG.LABEL_NOT_FOUND
Š ª à ¡®â ¥â
@echo off
echo Start
goto skip
echo <20>â® ­¥ ¢ë¯®«­¨âáï
:skip
echo <20>®á«¥ ¬¥âª¨
GOTO skip ? ä ©« ¯¥à¥¬ â뢠¥âáï ¢ ­ ç «®, áâப¨ ¯à®¯ã᪠îâáï (¡¥§ íå ) ¤® áâப¨ :skip, ¤ «¥¥ ¢ë¯®«­¥­¨¥ ¯à®¤®«¦ ¥âáï á echo <20>®á«¥ ¬¥âª¨.
<EFBFBD>®¤¤¥à¦¨¢ îâáï ¯¥à¥å®¤ë ¢¯¥àñ¤ ¨ ­ § ¤ (横«ë), ¡¥§ ãçñâ  à¥£¨áâà , ¯®¨áª ¬¥âª¨ ¨¤ñ⠮⠭ ç «  ä ©«  (¯¥à¢ ï ᮢ¯ ¢è ï ¬¥âª  ? ª ª ¢ MS-DOS).
‘âப¨ :¬¥âª  á ¬¨ ¯® ᥡ¥ ­¥ ¢ë¯®«­ïîâáï ¨ ­¥ íå®âáï.
…᫨ ¬¥âª¨ ­¥â ? ¢ë¢®¤¨âáï Label not found ¨ BAT-ä ©« ¯à¥à뢠¥âáï.
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
2. ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
’¥¯¥àì TAB ®áâ ñâáï ¢ áâப¥ ª ª ᨬ¢®« 0x09, ­® âà ªâã¥âáï ª ª ¯à®¡¥«ì­ë© à §¤¥«¨â¥«ì ⮫쪮 ¯à¨ à §¡®à¥ ­  ⮪¥­ë:
MOVWORD (BATCH.ASM) ? TAB ¡®«ìè¥ ­¥ § ¢¥àè ¥â áâபã: ¡ ©â á®åà ­ï¥âáï ¢ ¡ãä¥à ª ª ¥áâì, ª®­æ®¬ áâப¨ áç¨â îâáï ⮫쪮 CR/LF (<0x20, ªà®¬¥ 0x09).
‘âப¨ ­¥ à §à뢠îâáï ¯® â ¡ã«ï樨.
CMDMODE, .A826C (BATCH.ASM) ? ¢¥¤ã騥 ¯à®¡¥«ë ¨ â ¡ã«ï樨 ®¡à¥§ îâáï (®âáâã¯ë áâப).
CMDMODE, .A8276 (BATCH.ASM) ? £à ­¨æ  ?ª®¬ ­¤  /  à£ã¬¥­â? ⥯¥àì ¯® ¯à®¡¥«ã ¨«¨ â ¡ã«ï樨 (¢¬¥áâ® cpir ¯® ¯à®¡¥«ã).
<09>®í⮬ã GOTO?:PASS1 à á¯®§­ ñâáï ª ª ª®¬ ­¤  GOTO á  à£ã¬¥­â®¬ :PASS1.
cmd_goto / BAT_CHECK_LABEL (Commands/GOTO.ASM) ? ¯à®¯ã᪠¢¥¤ãé¨å ¯à®¡¥«®¢ ⥯¥àì ¢ª«îç ¥â TAB (¯®á«¥ ¨¬¥­¨ ª®¬ ­¤ë, ¯®á«¥ :),
áà ¢­¥­¨¥ ¬¥âª¨ ? ¡¥§ ãçñâ  à¥£¨áâà .
१ã«ìâ â¥:
@echo test 1?1234?=- ? ¢ë¢®¤¨âáï test 1?1234?=- á ­ áâ®ï饩 â ¡ã«ï樥© (0x09 ¯¥à¥¤ ñâáï ¢ ª®­á®«ì ç¥à¥§ Dss.PChars).
GOTO?:LABEL ¨ GOTO :LABEL ®¡  à ¡®â îâ; áâப¨-¬¥âª¨ :label ­¥ ¢ë¯®«­ïîâáï ¨ ­¥ íå®âáï; ®âáãâá⢨¥ ¬¥âª¨ ? Label not found ¨ ¯à¥à뢠­¨¥ BAT.
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
3. ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
GOSUB/RETURN ¤«ï BAT
Š ª ॠ«¨§®¢ ­®
GOSUB: § ¯à è¨¢ ¥â ⥪ã騩 㪠§ â¥«ì ä ©«  (Dss.Move_FP, B=1 ? ?tell?), ¢ëç¨á«ï¥â ᬥ饭¨¥ ­ ç «  á«¥¤ãî饩 áâப¨ = 㪠§ â¥«ì ? MOVWORD.count
(­¥¯à®ç¨â ­­ë¥ ¡ ©âë ¢ ¡ãä¥à¥), ª« ¤ñâ íâ® 32-¡¨â­®¥ ᬥ饭¨¥ ¢ á⥪ ¢®§¢à â®¢, § â¥¬ ¢ë¯®«­ï¥â ¯®¨áª ¬¥âª¨ ª ª GOTO.
RETURN: á­¨¬ ¥â ᬥ饭¨¥ á® á⥪ , ¯®§¨æ¨®­¨àã¥â ä ©« â㤠 (Dss.Move_FP, B=0), á¡à á뢠¥â ¡ãä¥à ? NEWLINE ¯à®¤®«¦ ¥â á® áâப¨ ¯®á«¥ GOSUB.
‘⥪ ¢®§¢à â®¢: gosub_stk (16?4 ¡ ©â ) + gosub_sp, á¡à á뢠¥âáï ¢ cmd_break.exit ¯à¨ ª ¦¤®¬ § ¢¥à襭¨¨ BAT.
Œ¥âª¨ ¨ ¯®¨áª ? ®¡é¨© ¬¥å ­¨§¬ á GOTO (goto_active/goto_label/BAT_CHECK_LABEL), TAB âà ªâã¥âáï ª ª ¯à®¡¥« ¯à¨ à §¡®à¥ (ª ª ¨ ¡ë«® ᤥ« ­® ¤«ï GOTO),
¯®í⮬ã GOSUB?:LABEL ⮦¥ à ¡®â ¥â.
Žè¨¡ª¨ (á®®¡é¥­¨¥ + ¯à¥à뢠­¨¥ BAT):
RETURN without GOSUB ? RETURN ¡¥§  ªâ¨¢­®£® GOSUB
GOSUB nesting too deep ? ¯¥à¥¯®«­¥­¨¥ á⥪  (>16)
Label not found ? ¬¥âª  GOSUB/GOTO ­¥ ­ ©¤¥­ 
ˆ§¬¥­ñ­­ë¥ ä ©«ë
SHELL/Commands/GOTO.ASM ? à¥ä ªâ®à¨­£ (®¡é¨¥ GOTO_PARSE/GOTO_START) + cmd_gosub, cmd_return, GOSUB_PUSH, á⥪, gAbort.
SHELL/BATCH.ASM ? ¢ BATLIST ¤®¡ ¢«¥­ë GOSUB/RETURN.
SHELL/Commands/BREAK.ASM ? á¡à®á á⥪  GOSUB ¯à¨ § ¢¥à襭¨¨ BAT.
SHELL/Messages/main_txt.asm ? á®®¡é¥­¨ï RETURN without GOSUB, GOSUB nesting too deep.
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
4. ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
IF ¤«ï BAT
<EFBFBD>®¤¤¥à¦¨¢ ¥¬ë© ᨭ⠪á¨á
IF [NOT] ERRORLEVEL ç¨á«® ª®¬ ­¤ 
IF [NOT] EXIST ä ©« ª®¬ ­¤ 
IF [NOT] áâப 1==áâப 2 ª®¬ ­¤ 
…᫨ ãá«®¢¨¥ ¨á⨭­® ? ®áâ â®ª áâப¨ ¢ë¯®«­ï¥âáï ª ª ®¡ëç­ ï ª®¬ ­¤  (GOTO, GOSUB, ECHO, § ¯ã᪠¯à®£à ¬¬ë, ¢«®¦¥­­ë© IF ¨ â.¤.).
‘¥¬ ­â¨ª  (ª ª ¢ MS-DOS)
ERRORLEVEL n ? ¨á⨭ , ¥á«¨ ª®¤ § ¢¥à襭¨ï ¯à¥¤ë¤ã饩 ¯à®£à ¬¬ë >= n (ç¥à¥§ Dss.Get_Err #42). —¨á«® 0..255.
EXIST ä ©« ? ¨á⨭ , ¥á«¨ ä ©«/ª â «®£ áãé¥áâ¢ã¥â (ç¥à¥§ Dss.F_First,  âਡãâë ?¢áñ, ªà®¬¥ ¬¥âª¨ ⮬ ?).
áâப 1==áâப 2 ? ¯®á¨¬¢®«ì­®¥ áà ¢­¥­¨¥ á ãçñ⮬ ॣ¨áâà  (ª ª ¢ COMMAND.COM). <20> §¤¥«¨â¥«ì ? ==.
NOT ? ¨­¢¥àá¨ï ãá«®¢¨ï.
%VAR% / %1 㦥 ¯®¤áâ ¢«¥­ë EVALCMD ¤® ¢ë¯®«­¥­¨ï IF, ¯®í⮬ã à ¡®â ¥â ª« áᨪ  IF "%1"=="" GOTO end.
TAB âà ªâã¥âáï ª ª ¯à®¡¥« (ᮣ« á®¢ ­® á à ­¥¥ ᤥ« ­­ë¬ ¤«ï GOTO).
Š ª à ¡®â ¥â ¯®¢â®à­ ï ¤¨á¯¥âç¥à¨§ æ¨ï
<EFBFBD>®á«¥ ¯à®¢¥àª¨ ãá«®¢¨ï IF_RUN ­ å®¤¨â ­ ç «® ª®¬ ­¤ë-®áâ âª , ¢ëç¨á«ï¥â ¤«¨­ã ¥ñ ⮪¥­  ¨ ¤¥« ¥â jp COMP.start á hl=BATLIST ? â®â ¦¥ ¯ãâì,
çâ® ¨ ¤«ï ®¡ëç­®© áâப¨. <20>®í⮬ã IF ? GOTO :label, IF ? GOSUB :sub, IF ? program.exe, ¨ ¢«®¦¥­­ë¥ IF a==b IF c==d ? à ¡®â îâ
(ç¥à¥§ jp, ¡¥§ à®áâ  á⥪ ). …᫨ ãá«®¢¨¥ «®¦­® ¨«¨ ª®¬ ­¤  ¯ãáâ  ? ret (­¨ç¥£® ­¥ ¤¥« ¥âáï).
ˆ§¬¥­ñ­­ë¥ ä ©«ë
SHELL/Commands/IF.ASM ? ­®¢ë©: cmd_if, IF_KW (ॣ¨áâà®­¥§ ¢¨á¨¬®¥ à á¯®§­ ¢ ­¨¥ ª«î祢ëå á«®¢), IF_ATOI8, IF_SKIPB, IF_RUN.
SHELL/SHELL.ASM ? include 'Commands/if.asm'.
SHELL/BATCH.ASM ? IF ¤®¡ ¢«¥­ ¢ BATLIST (batch-only, ª ª GOTO/GOSUB).
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

View File

@ -2,7 +2,16 @@
cmd_break:
.sp+1: LD SP,0
;!TODO ¢«®¦¥­­ë¥ bat. ¯¥à¥¤ ¢ âì ®è¨¡ªã ®¡à â­® ¢ ¢ë§ë¢ î騩 bat
.exit: ld a,(BAT_FM) ; ¤¥áªà. bat-ä ©« 
.exit: ld a,(goto_active) ; GOTO: label not found ?
or a
jr z,.close
xor a
ld (goto_active),a
ld de,MAIN_MSG.LABEL_NOT_FOUND
call ECHO_MESSAGE
.close: xor a
ld (gosub_sp),a ; reset GOSUB stack
ld a,(BAT_FM) ; ¤¥áªà. bat-ä ©« 
ld c,Dss.Close ; § ªàëâì ä ©«
RST ToDSS
xor a

275
SHELL/Commands/GOTO.ASM Normal file
View File

@ -0,0 +1,275 @@
;///////////////////////////////////////////////////
;
; 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)

241
SHELL/Commands/IF.ASM Normal file
View File

@ -0,0 +1,241 @@
;///////////////////////////////////////////////////
;
; IF - conditional command (MS-DOS style)
;
; IF [NOT] ERRORLEVEL number command
; IF [NOT] EXIST filename command
; IF [NOT] string1 == string2 command
;
; If the condition is true, the rest of the line is
; executed as an ordinary command (GOTO, ECHO, a
; program, another IF, ...).
;
;///////////////////////////////////////////////////
; in: de -> argument string (everything after "IF ")
cmd_if:
ex de,hl ; hl -> args
xor a
ld (.neg),a
call IF_SKIPB ; skip leading blanks
; --- optional NOT ---
ld de,.kw_not
call IF_KW
jr nc,.noNOT
ld a,1
ld (.neg),a
.noNOT:
; --- ERRORLEVEL n ? ---
ld de,.kw_errlvl
call IF_KW
jr nc,.notErr
ld de,Buffers.work.buffer1
ld c,Dss.GSwitch ; extract the number token
RST ToDSS
ld (.cmd),hl ; rest of line = command part
ld de,Buffers.work.buffer1
call IF_ATOI8 ; a = number (0..255)
ld b,a ; b = threshold
ld c,Dss.Get_Err ; a = exit code of last program
RST ToDSS
cp b ; A >= n ? (NC = yes)
ld a,0
jr c,.decide ; A < n -> false
inc a ; true
jr .decide
.notErr:
; --- EXIST filename ? ---
ld de,.kw_exist
call IF_KW
jr nc,.strcmp
ld de,Buffers.work.buffer1
ld c,Dss.GSwitch ; extract the filename token
RST ToDSS
ld (.cmd),hl ; rest of line = command part
ld a,FAT_ATTR.NoVolID ; any file/dir (not the volume label)
ld hl,Buffers.work.buffer1 ; filespec (NUL-term DOS name)
ld de,Buffers.work.buffer2 ; F_First work buffer
ld bc,Dss.F_First.DOSname ; B=1, C=#19
RST ToDSS
ld a,0
jr c,.decide ; CF=1 -> not found -> false
inc a ; exists -> true
jr .decide
.strcmp:
; hl -> string1 "==" string2 [blank] command
push hl ; s1 start
.find: ld a,(hl)
or a
jr z,.bad ; no "==" -> malformed
cp "="
jr nz,.fnext
inc hl
ld a,(hl)
cp "="
jr z,.foundEq
dec hl
.fnext: inc hl
jr .find
.bad: pop hl
ret ; syntax error -> no-op
.foundEq:
dec hl ; hl -> first '=' of "=="
pop de ; de = s1 start
push de
or a
sbc hl,de ; hl = len1 (line < 256 -> h=0)
ld a,l
ld (.len1),a
pop de ; de = s1 start
ld hl,0
ld l,a
add hl,de ; hl = s1 + len1 = first '='
inc hl
inc hl ; hl = s2 start
ld (.s2),hl
ld b,0 ; len2
.s2l: ld a,(hl)
cp " "+1 ; <=' ' (space/tab/CR/0) -> token end
jr c,.s2e
inc hl
inc b
jr .s2l
.s2e: ld (.cmd),hl ; command part starts here
ld a,(.len1)
cp b ; len1 == len2 ?
jr nz,.neq
or a
jr z,.eq ; both empty -> equal
ld c,a ; c = length
ld hl,(.s2)
.cl: ld a,(de) ; de = s1
cp (hl) ; case-sensitive (MS-DOS)
jr nz,.neq
inc de
inc hl
dec c
jr nz,.cl
.eq: ld a,1
jr .decide
.neq: xor a
;
.decide:
; a = raw condition (0/1)
ld b,a
ld a,(.neg)
xor b ; cond ^ NOT
and 1
ret z ; false -> nothing to do
ld hl,(.cmd)
jp IF_RUN ; true -> run the command part
;
.kw_not: db "NOT",0
.kw_errlvl: db "ERRORLEVEL",0
.kw_exist: db "EXIST",0
.neg: db 0
.cmd: dw 0
.len1: db 0
.s2: dw 0
;-------------------------------------------------
; Skip blanks (space / TAB) at (hl)
;-------------------------------------------------
IF_SKIPB:
.l: ld a,(hl)
cp " "
jr z,.i
cp "\t"
ret nz
.i: inc hl
jr .l
;-------------------------------------------------
; Case-insensitive keyword test.
; in: hl -> text, de -> keyword (UPPER, 0-term)
; out: CF=1 - matched, hl past keyword + blanks
; CF=0 - no match, hl unchanged
;-------------------------------------------------
IF_KW: push hl
.l: ld a,(de)
or a
jr z,.kend ; keyword consumed
ld c,a
ld a,(hl)
call COMPARE.cmp_AZ ; -> upper
cp c
jr nz,.no
inc hl
inc de
jr .l
.kend: ld a,(hl) ; must be a blank delimiter
cp " "
jr z,.ok
cp "\t"
jr z,.ok
.no: pop hl ; restore, no match
or a ; CF=0
ret
.ok: inc hl ; skip delimiter + following blanks
.ok2: ld a,(hl)
cp " "
jr z,.oki
cp "\t"
jr nz,.done
.oki: inc hl
jr .ok2
.done: pop bc ; discard saved hl
scf
ret
;-------------------------------------------------
; ASCII decimal -> A (0..255, saturating)
; in: de -> digits
;-------------------------------------------------
IF_ATOI8:
ld hl,0
.l: ld a,(de)
sub "0"
jr c,.end
cp 10
jr nc,.end
ld c,a ; c = digit
ld b,0
push de
ld d,h
ld e,l
add hl,hl ; *2
add hl,hl ; *4
add hl,de ; *5
add hl,hl ; *10
add hl,bc ; + digit
pop de
inc de
jr .l
.end: ld a,h
or a
jr nz,.sat
ld a,l
ret
.sat: ld a,255
ret
;-------------------------------------------------
; Run the conditional command.
; in: hl -> command text (NUL-term at line end)
;-------------------------------------------------
IF_RUN:
call IF_SKIPB
ld a,(hl)
or a
ret z ; empty -> no-op
ld d,h
ld e,l ; de = command start
ld bc,0 ; b=0, c = token length
.tl: ld a,(hl)
cp " "+1 ; <=' ' -> end of command token
jr c,.tle
inc hl
inc c
jr .tl
.tle: ld hl,BATLIST ; bat + dos commands
jp COMP.start ; dispatch (recurses for nested IF)

View File

@ -25,6 +25,9 @@ MAIN_MSG:
.INFO_2 EQU .INFO_2_
.DIRPAUSE EQU .DIRPAUSE_
.CLSLINE EQU .CLSLINE_
.LABEL_NOT_FOUND EQU .LBLNF_
.RET_NO_GOSUB EQU .RNGSB_
.GOSUB_DEEP EQU .GSBDP_
;
!txtCounter DEFL 0
; ; ­¥ ᤢ¨£ âì____
@ -55,6 +58,9 @@ MAIN_MSG:
stN .INFO_2_ : DZ " %9 \r\t %8\r\t\t\t %7\r\t\t\t\t\t %4\r\t\t\t\t\t\t\t %5\r\n"
stN .DIRPAUSE_ : DZ "Press ESC to cancel or any other key to continue . . .\r"
stN .CLSLINE_ : DZ " \r"
stN .LBLNF_ : DZ "Label not found\r\n"
stN .RNGSB_ : DZ "RETURN without GOSUB\r\n"
stN .GSBDP_ : DZ "GOSUB nesting too deep\r\n"
; ;R11
db 0
DZ "Unknown command"

View File

@ -535,6 +535,8 @@ T8C24: db "OFF",0
;
include 'Commands/exit.asm' ; ¢ë室 ¢ த¨â. ¯à®æ¥áá
include 'Commands/break.asm' ; ¢ë室 ¨§ ¯ àá¥à  bat
include 'Commands/goto.asm' ; GOTO - jump to a label in a bat
include 'Commands/if.asm' ; IF - conditional command
include 'Commands/pause.asm' ; ¯ ã§ 
include 'Commands/rem.asm' ; ª®¬¬¥­â à¨©
include 'Commands/ver.asm' ; ¢ë¢®¤ ¢¥àᨨ „Ž‘

@ -1 +1 @@
Subproject commit 90d829290d3946ab99952128f4717dde577ced04
Subproject commit 591d3212c9341f17d6dd034bf2b8da91bd2f6107