Как получить сумму из 2 чисел в оригинальном DOS? - PullRequest
0 голосов
/ 12 января 2019

Я хотел пережить ностальгию по старым добрым душам.
Я тестировал несколько пакетных команд, но заметил, что /a не может использоваться в DOS.
Есть ли другой метод, который я могу использовать, чтобы добавить две переменные без включения /a?

@echo off
::this is how I would originally add two numbers
set /p number1=
set /p number2=
set /a "number1=number1+number2"
echo %number1%
pause >nul
exit

dos сообщает "invalid switch. - /a", когда я запускаю эту программу.

Ответы [ 3 ]

0 голосов
/ 15 января 2019

Это как можно ближе. Поскольку основной сценарий называется sum.bat, укажите два числа в качестве аргументов командной строки.

Вот код sum.bat:

@echo off & > nul ver
rem // Define constants here:
set SUB=.\sum-sub.bat
set FILE=.\sum.tmp
set RESULT=.\sum-res.tmp
rem // Check if enough arguments are provided:
if "%2"=="" (>&2 echo ERROR: too few arguments!) & < nul find "" & goto :END
rem // Initialise variables:
set LIST=
rem // Create list of as many space-separated `#` symbols as given by 1st number:
call %SUB% %1
rem // Append list by as many space-separated `#` symbols as given by 2nd number:
call %SUB% %2
rem // Terminate execution in case of unsupported numbers:
if ErrorLevel 1 goto :END
rem // Create empty temporary file:
> nul copy /Y nul %FILE%
rem // Fill temporary file with as many bytes as list items are given:
for %%I in (%LIST%) do (> nul copy /B %FILE% + nul %FILE% /A)
rem // Get size of temporary file, filter out first summary line and store in file:
dir /A:-D /-W /-C %FILE% | find "1 File(s)" > %RESULT%
rem /* Read from file the summary line but display it without "1 File(s)" prefix;
rem    since this is searched literally, the code becomes language-dependent;
rem    the "bytes" suffix unfortunately remains: */
< %RESULT% (
    for %%I in (# # # # # # # # # # # # # # # # # # # # # # # #) do > nul pause
    sort & echo/
)
rem // Clean up temporary files:
del %FILE% %RESULT%
:END

Вот код подпрограммы sum-sub.bat:

@echo off
rem // Jump to correct entry point to create/append a list with correct length:
2> nul goto :$%1 & < nul find "" & >&2 echo ERROR: unexpected argument!
rem // Do not add anything to the list upon errors:
goto :$0
rem /* Inverse list to add as many space-separated `#` symbols as given by the argument;
rem    extend it in the same manner in order to support numbers greater than `12`: */
:$12
set LIST=%LIST% #
:$11
set LIST=%LIST% #
:$10
set LIST=%LIST% #
:$9
set LIST=%LIST% #
:$8
set LIST=%LIST% #
:$7
set LIST=%LIST% #
:$6
set LIST=%LIST% #
:$5
set LIST=%LIST% #
:$4
set LIST=%LIST% #
:$3
set LIST=%LIST% #
:$2
set LIST=%LIST% #
:$1
set LIST=%LIST% #
:$0

Вот несколько примеров использования:

>>> sum.bat 1 0
             19 bytes

>>> sum.bat 3 6
              9 bytes

>>> sum.bat 2
ERROR: to few arguments!

>>> sum.bat 1 0
             19 bytes

>>> sum.bat 13 4
ERROR: unexpected argument!

Я должен признать, что я тестировал этот подход в командной строке Windows с отключенными расширениями команд, но не в реальной среде MS-DOS.

0 голосов
/ 16 января 2019

Это немного сложнее, чем использовать set /a, но это можно решить с помощью MS-DOS 6.22.

Одна часть состоит в написании функции для добавления отдельных цифр и одной функции, которая может добавлять несколько цифр.

Основная проблема - разделить число на однозначные числа, поскольку MS-DOS не поддерживает манипуляции со строками.
Но в обработке FOR-Loop есть небольшой недостаток: / разбивает текст на три части.

for %%a in (`abcdef/ghijklmno`) do echo %%a

Выходы

abcdef
g
hijklmno

С помощью этого трюка число можно разбить на однозначные числа

split.bat

@echo off
for %%P in (/%1.) do if %%P==: goto %1

set _idx=
set _remain=
set _splitRev=
set _splitRev_comma=

:loop

set _loop=1

for %%a in (/%_remain%) do call %0 :split %1 %%a
if NOT "%_remain%"=="" goto :loop
set %1=%_splitRev%
set %1_comma=%_splitRev_comma%

REM Clear temp vars
FOR %%v in (_remain _idx _loop _splitRev _splitRev_comma) do set %%v=
goto :eof

:split
if %_loop%%==2 goto :split_2
set _loop=2
set _remain=
set splitRev=%3%_splitRev%
set splitRev_comma=%3,%_splitRev_comma%
goto :eof

:split_2
set _remain=%3
goto :eof

:eof

А add.bat выглядит как

@echo off
for %%P in (/%1.) do if %%P==: goto %1

call splitt _valueRev1 %1
call splitt _valueRev2 %2

set _result=
set _carry=
for %%d in(%_valueRev1_comma%,0,0,0,0,0) do call %0 :getDig1 %%d

REM Remove leading zeros
:zeroLoop
for %%z in (/%_result%) do set _remain=%%z
if not %_result%==0%_remain% goto :finish
set _result=%_remain%
goto :zeroLoop

:finish
echo %1+%2=%_result%

REM Clear temp vars
FOR %%v in (_result _carry _len _digit1 _digit2 _remain _valueRev1 _valueRev1_comma _valueRev2 _valueRev2_comma) do set %%v=
goto :eof

:getDig1
set _digit1=%2
set _digit2=
for %%d in (/%_valueRev2%0) do call %0 :getDig2 %%d

set _len=%_carry%
call %0 :lenAddDigit %_digit1%
call %0 :lenAddDigit %_digit1%
call %0 :len2val
set _result=%_val%%_result%
goto :eof

:getDig2if not "%_digit2%"==" set _valueRev2=%2
if "%_digit2%"=="" set _digit2=%2
goto :eof

:lenAddDigit
if %2==1 set _len=%_len%#
if %2==2 set _len=%_len%##
if %2==3 set _len=%_len%###
if %2==4 set _len=%_len%####
if %2==5 set _len=%_len%#####
if %2==6 set _len=%_len%######
if %2==7 set _len=%_len%#######
if %2==8 set _len=%_len%########
if %2==9 set _len=%_len%#########
goto :eof

:len2val
set _carry=
set _val=
if %_len%.==. set _val=0
if %_len%.==. goto :eof
if %_len%==# set _val=1
if %_len%==## set _val=2
if %_len%==### set _val=3
if %_len%==#### set _val=4
if %_len%==##### set _val=5
if %_len%==###### set _val=6
if %_len%==####### set _val=7
if %_len%==######## set _val=8
if %_len%==######### set _val=9
if NOT "%_val%"=="" goto :eof
set _carry=#
##########
if %_len%==########## set _val=0
if %_len%==########### set _val=1
if %_len%==############ set _val=2
if %_len%==############# set _val=3
if %_len%==############## set _val=4
if %_len%==############### set _val=5
if %_len%==################ set _val=6
if %_len%==################# set _val=7
if %_len%==################## set _val=8
if %_len%==################### set _val=9
goto :eof

:eof

Успешно протестировано на MS-DOS 6.22 (VMWare)

Ограничения MS-DOS 6.22

  1. IF не поддерживает ELSE

    Обход:

    IF %1==b echo It is equal
    IF NOT %1==b echo It isn't equal
    
  2. Только goto может перейти к метке, CALL может только запустить другую партию.

    Решение:

    Поместите что-то подобное в первую строку вашей партии

    FOR %%P in (/%1) do IF %%P==: goto %1
    ...
    REM This calls the current batch file and jumps to a label
    CALL %0 :myLabel arg1
    ...
    :myLabel
    echo arg1=%2
    echo Action1
    echo Action2
    goto :eof
    
  3. Нет кодовых блоков, как

    FOR %%a in (1 2 3 ) do ( 
      set concat=%%a
      echo %concat%
    )
    

    Обходной путь:

    FOR %%a in (1 2 3 ) do CALL %0 :myFunc %%a
    
  4. Нет косвенного расширения переменных

    Обходной путь:

    set var=content
    set indirect=var
     > temp$$$.bat echo set result=%%%indirect%%%
    call temp$$$.bat
    echo result=%result%
    
0 голосов
/ 12 января 2019

Если вы пытаетесь сделать это из реальной DOS (а не из эмуляции Windows из 32-битной эры), это просто невозможно, если вы вручную не обработаете каждую возможную пару чисел, которые вы могли бы использовать в качестве ввода (что становится неуправляемым) когда вы идете выше однозначных).

Это всегда был большой недостаток пакетных файлов DOS, который обычно исправлялся путем вызова небольших сценариев на реальных языках сценариев (таких как BASIC), часто записываемых тем же файлом .bat, который их вызывал. Это, конечно, требует наличия переводчика для вашего языка.

...