diff --git a/SHELL/BATCH.ASM b/SHELL/BATCH.ASM index 058fe0e..1572683 100644 --- a/SHELL/BATCH.ASM +++ b/SHELL/BATCH.ASM @@ -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 diff --git a/SHELL/Changes.txt b/SHELL/Changes.txt new file mode 100644 index 0000000..1957c07 --- /dev/null +++ b/SHELL/Changes.txt @@ -0,0 +1,91 @@ +Что сделано: +1. █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + GOTO для BAT +Новый файл 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 Это не выполнится +:skip +echo После метки +GOTO skip ? файл перематывается в начало, строки пропускаются (без эха) до строки :skip, далее выполнение продолжается с echo После метки. +Поддерживаются переходы вперёд и назад (циклы), без учёта регистра, поиск метки идёт от начала файла (первая совпавшая метка ? как в 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 по пробелу). + Поэтому 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 +Поддерживаемый синтаксис + +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). Разделитель ? ==. +NOT ? инверсия условия. +%VAR% / %1 уже подставлены EVALCMD до выполнения IF, поэтому работает классика IF "%1"=="" GOTO end. +TAB трактуется как пробел (согласовано с ранее сделанным для GOTO). +Как работает повторная диспетчеризация +После проверки условия IF_RUN находит начало команды-остатка, вычисляет длину её токена и делает jp COMP.start с hl=BATLIST ? тот же путь, + что и для обычной строки. Поэтому 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). +████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ \ No newline at end of file diff --git a/SHELL/Commands/BREAK.ASM b/SHELL/Commands/BREAK.ASM index 55e7b69..1c57e98 100644 --- a/SHELL/Commands/BREAK.ASM +++ b/SHELL/Commands/BREAK.ASM @@ -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 diff --git a/SHELL/Commands/GOTO.ASM b/SHELL/Commands/GOTO.ASM new file mode 100644 index 0000000..082c71b --- /dev/null +++ b/SHELL/Commands/GOTO.ASM @@ -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) diff --git a/SHELL/Commands/IF.ASM b/SHELL/Commands/IF.ASM new file mode 100644 index 0000000..50e949f --- /dev/null +++ b/SHELL/Commands/IF.ASM @@ -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) diff --git a/SHELL/Messages/main_txt.asm b/SHELL/Messages/main_txt.asm index 28a686b..2403d87 100644 --- a/SHELL/Messages/main_txt.asm +++ b/SHELL/Messages/main_txt.asm @@ -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" diff --git a/SHELL/SHELL.ASM b/SHELL/SHELL.ASM index f350eb4..b97a379 100644 --- a/SHELL/SHELL.ASM +++ b/SHELL/SHELL.ASM @@ -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' ; вывод версии ДОС diff --git a/Shared_Includes b/Shared_Includes index 90d8292..591d321 160000 --- a/Shared_Includes +++ b/Shared_Includes @@ -1 +1 @@ -Subproject commit 90d829290d3946ab99952128f4717dde577ced04 +Subproject commit 591d3212c9341f17d6dd034bf2b8da91bd2f6107