Advertisement
Abaduaber

PSP

Dec 29th, 2019
715
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;Задание 6, вариант 12.
  2. ;Выдать все строки с номерами 21 и 55
  3. ;Выдать все строки с символом "
  4. .MODEL TINY           ;Будем использовать формат исполняемого файла COM
  5. .CODE                 ;Сегмент кода (он же в нашем случае и сегмент данных и стека одновременно)
  6. ORG 100h              ;Программный счетчик ставим на 100h, это требуется для COM файлов.
  7. Begin:
  8.                       ;По началу из-за особенностей COM файлов у нас CS = SS = DS = ES.
  9.                       ;То есть мы будем использовать один сегмент для всего. Стек при этом растет с конца
  10.     JMP Main          ;Переходим на стартовую метку программы                              
  11.  
  12.  
  13.     ReqNum1 EQU 21                       ;Требуемые номера
  14.     ReqNum2 EQU 55
  15.     ReqChar = """"                       ;требуемый символ. Повторен 2 раза из-за экранирования.
  16.                                          ;Т.к помещаем двойные кавычки в двойные кавычки.
  17.     ;Далее текстовый строки. Для удобства форматирования вывода могут содержать
  18.     ;в себе символы новой строки и перевода каретки.
  19.     NotFoundNum1  DB  "Строка с номером 21 не найдена", 13, 10, "$"
  20.     NotFoundNum2  DB  "Строка с номером 55 не найдена", 13, 10, "$"
  21.     NotFoundChar  DB "Строка, содержащая символ "" не найдена", 13, 10, "$"
  22.     StringN       DB "Строка с символом "": $"
  23.     StringNum1    DB  "Строка #21: $"
  24.     StringNum2    DB  "Строка #55: $"
  25.     CRLF          DB  13, 10, "$"
  26.     StrI          DB 1                   ;Текущий номер строки
  27.     LastFlag      DB 0                   ;Была ли найденная строка последней?
  28.     StartPosition DW 0                   ;Позиция и длина последней найденной строки
  29.     StartLength   DW 0
  30.     Num1Out       DB 0                     ;Флаги. Хранят статус факта вывода строк
  31.     Num2Out       DB 0
  32.     CharOut       DB 0
  33.  
  34.     LaunchString DB "Строка запуска программы #   : $"
  35.  
  36.                                          ;Начало сегмента кода
  37. Main:                                    ;Главная функция. С нее начинается работа программы
  38.     MOV    AX,[ES:2Ch]                   ;AX - сегмент переменных среды
  39.     MOV    ES,AX                         ;ES теперь - сегмент переменных среды
  40.  
  41.   CheckLoop:
  42.     CALL   GetString                     ;Получаем строку
  43.     CALL   CheckStrForSymbols            ;Проверяем ее на наличие требуемых символов
  44.     CALL   CheckNumber                   ;Проверяем строку по номерам (нужно ли выводить)
  45.     INC    BYTE PTR [StrI]               ;Переходим к следующей строке
  46.     CMP    BYTE PTR [LastFlag],1         ;Если строки еще остались - прочитаем еще
  47.     JNE    CheckLoop
  48.     CMP    BYTE PTR [Num1Out],1          ;Если первая строка не была выведена
  49.     JE     CheckNext
  50.     MOV    DX,OFFSET NotFoundNum1        ;То доложим об этом, как требует условие
  51.     CALL   Print
  52.   CheckNext:
  53.     CMP    BYTE PTR [Num2Out],1          ;Тоже самое и для второй строки
  54.     JE     SkipIt
  55.     MOV    DX,OFFSET NotFoundNum2
  56.     CALL   Print
  57.   SkipIt:
  58.     CMP    BYTE PTR [CharOut],0         ;И тоже самое для строки с символом
  59.     JNZ    Done
  60.     MOV    DX,OFFSET NotFoundChar       ;Выведем сообщение, если не находили таких строк
  61.     CALL   Print
  62.   Done:
  63.     ;Теперь остается вывести строку запуска программы и ее номер.
  64.     ;Сейчас DI практически на нее указывает, не считая 3 байт.
  65.     MOV    SI,OFFSET LaunchString + 28  ;SI будет указывать
  66.    
  67.     ;Чтобы получить строку номера - придется делить:
  68.     MOV    AL,[StrI]                    ;AL - номер строки
  69.     MOV    BL,10                        ;Делить будет на 10
  70.   DivLoop:
  71.     XOR    AH,AH                        ;Обнулим остаток
  72.     DIV    BL                           ;Делим. В AH попадет остаток от деления
  73.     MOV    BYTE PTR [SI],AH             ;Записываем его в строку
  74.     ADD    BYTE PTR [SI],"0"            ;И превращаем в символ числа
  75.     DEC    SI                           ;К предыдущему символу
  76.     TEST   AL,AL                        ;Продолжаем, пока результат не 0
  77.     JNZ    DivLoop
  78.     MOV    DX,OFFSET LaunchString       ;Выведем комментарий к строке вместе с номером
  79.     CALL   Print
  80.     ADD    DI,3                         ;Заставим DI указывать на строку запуска
  81.     CALL   GetString                    ;И отобразим ее тоже.
  82.     CALL   Output
  83.     MOV    AX,4C00h                      ;Завершаем программу и выходим в DOS
  84.     INT    21h
  85.  
  86. ;Проверяет, какой номер у полученной строки. Если его нужно вывести - выводит
  87. CheckNumber:
  88.     MOV    AL,ReqNum1                   ;AL - первый из номеров итнересующих нас строк
  89.     CMP    BYTE PTR [StrI],AL           ;Индекс текущей строки совпадает с ним?
  90.     JNE    CheckSecond                  ;нет - переходим к следующей
  91.     MOV    DX,OFFSET StringNum1         ;Иначе выводим сообщение, что строка найдена
  92.     CALL   Print
  93.     MOV    DI,[StartPosition]           ;И саму строку
  94.     MOV    CX,[StartLength]
  95.     CALL   Output
  96.     MOV    DX,OFFSET CRLF
  97.     CALL   Print
  98.     MOV    BYTE PTR [Num1Out],1
  99.     INC    DI
  100.     ;Вывести первую строку
  101.   CheckSecond:
  102.     MOV    AL,ReqNum2                  ;Аналогично и для второй строки
  103.     CMP    BYTE PTR [StrI],AL
  104.     JNE    NotThisTime
  105.     MOV    DX,OFFSET StringNum2
  106.     CALL   Print
  107.     MOV    DI,[StartPosition]
  108.     MOV    CX,[StartLength]
  109.     CALL   Output
  110.     MOV    DX,OFFSET CRLF
  111.     CALL   Print
  112.     MOV    BYTE PTR [Num2Out],1
  113.     INC    DI
  114.   NotThisTime:
  115.     RET
  116.  
  117. ;Проверяет, имеются ли в полученной строке искомый нами символ.
  118. ;Если да - выводит такую строку
  119. ;Предполагает, что на входе CX - длина строки, DI - ее начало
  120. CheckStrForSymbols:
  121.     MOV    [StartPosition],DI           ;Сохраняем в переменные начало строки и ее длину
  122.     MOV    [StartLength],CX
  123.     MOV    AH,ReqChar                   ;Ah - код интеерсующего нас символа
  124.   NewChar:
  125.     CMP    [ES:DI],AH                   ;Является ли текущий символ строки искомым?
  126.     JE     Found                        ;Если да, перейдем к выводу строки
  127.     INC    DI                           ;Иначе проверим следующий символ
  128.     DEC    CX
  129.     JNZ    NewChar                      ;Пока строка не кончилась
  130.     JMP    NotFound
  131.   Found:
  132.     MOV    BYTE PTR [CharOut],1         ;Ставим флаг, что нашли хоть одну строку с указанным символом
  133.     MOV    DX,OFFSET StringN            ;И выводим эту строку с комментарием
  134.     CALL   Print
  135.     MOV    DI,[StartPosition]
  136.     MOV    CX,[StartLength]
  137.     CALL   Output
  138.     MOV    DX,OFFSET CRLF
  139.     CALL   Print
  140.     INC    DI
  141.     RET
  142.   NotFound:
  143.     INC    DI
  144.     RET
  145.  
  146. ;Получает очередную строку из сегмента переменных среды.
  147. ;Предполагает, что ES:DI - сегмент переменных среды
  148. ;Устанавливает LastFlag в 1, если полученная строка была последней. Иначе 0.
  149. ;На выходе DI - начало строки. CX - ее длина.
  150. GetString:
  151.     PUSH   DI
  152.     MOV    CX,65535                       ;Ведем поиск по всему сегменту
  153.     XOR    AL,AL                          ;Ищем нули
  154.     CLD                                   ;Направление поиска на инкремент
  155.     REPNE  SCASB                          ;Ищем
  156.     CMP    BYTE PTR [ES:DI],0             ;Если сразу же после нуля есть еще один
  157.     JE     LastString                     ;то это была последняя строка
  158.  
  159.     POP    DI                             ;Восстановим старое значение указателя на строку
  160.     NEG    CX                             ;И приведем в порядок CX, чтобы показывал длину найденной строки
  161.     SUB    CX,2
  162.     RET
  163.   LastString:
  164.     POP    DI                             ;Аналогично и тут
  165.     NEG    CX
  166.     SUB    CX,2
  167.     MOV    BYTE PTR [LastFlag],1
  168.     RET
  169.  
  170. ;Выводит строку символов с помощью функции AH-02h прерывания INT 21h
  171. ;Начало строки -  ES:DI. Символы выводятся в количестве CX штук
  172. Output:
  173.     MOV    AH,02h                        ;INT 21h, 02h - вывод символа
  174.   StartLoop:
  175.     MOV    DL,[ES:DI]                    ;DL - код текущего символа строки
  176.     INT    21h                           ;Выводим
  177.     INC    DI                            ;и переходим к следующему символу
  178.     LOOP   StartLoop                     ;Так, пока не отобразим все CX символов
  179.   ExitLoop:
  180.     RET
  181.  
  182. Print:                                   ;Просто функция вывода строки, чтобы
  183.     MOV    AH,09H                        ;писать не 3 строчки на вывод, а две.
  184.     INT    21h
  185.     RET
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement