БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
ИНФОРМАТИКИ И РАДИОЭЛЕКТРОНИКИ
Кафедра программного обеспечения информационных технологий
Факультет ФКСиС
Специальность ПОИТ
Индивидуальная практическая работа № 1
по дисциплине «Языки программирования часть 1»
Вариант 5
Выполнил студент: Бордон Е.С.
группа 991051
Зачетная книжка № 99105004
Минск 2021
Условия задачи
Написать и отладить программу на языке Ассемблер.
Найти расстояние между указанными элементами в строке
(использовать команду scas). Строку описать в сегменте данных.
Пояснения к работе программы
Программы написаны на Assembler для MASM для выполнения на современных 32-битных процессорах в ОС Windows с использованием среды разработки SASM и отладчика OllyDbg.
Программа содержит предопределённую в сегменте данных строку для сравнения («The string of text») и принимает от пользователя 2 символа для сравнения его с символами строки. Сравнение осуществляется функцией scasb в цикле, организованном с помощью меток.
Программа рассчитывает расстояние в символах между указанными элементами, от начала строки с лево на право. В программе предусмотрена защита от ввода одинаковых символов и отсутствия символов в строке.
Результат работы программы
Рис 1. Результат работы программы
Тестовый набор данных:
Первый символ |
Второй символ |
Расстояние |
s |
t |
0 |
T |
f |
11 |
x |
g |
8 |
Листинг программы
.386 ; код скомпилируется для сравнительно современных 32-битных процессоров
.model flat, stdcall ; устанавливаем модель памяти windows, очистку стека осуществляет вызываемая подпрограмма
option casemap : none ; делаем переменные регистрозависимыми
include \masm32\include\kernel32.inc ; для использования базового API Windows
include \masm32\include\msvcrt.inc ; для использования crt_printf и crt_scanf (ввод/вывод с поддержкой формата)
includelib \masm32\lib\kernel32.lib ; для использования базового API Windows
includelib \masm32\lib\msvcrt.lib ; для использования crt_printf и crt_scanf (ввод/вывод с поддержкой формата)
CRLF equ 13, 10 ; синоним перевода строки в консоли
.data ; сегмент данных
cmpStr db "The string of text", 0 ; строка для сравнения
; далее 4 переменные с фрагментами текста для общения с пользователем
cmpStrComment db "The string for comparement is: ", 0 ; строка для сравнения 18 символов
msgInviteInput db CRLF, "Enter the first character to compare: ", 0 ; строка-приглашение ввести символ для сравнения
msgInviteInputt db CRLF, "Enter the second character to compare: ", 0 ; строка-приглашение ввести символ для сравнения
msgRes db "Distance between characters: ", 0 ; текст вступления перед выводом результата вычислений
msgError db "Error! Identical symbols!", 0 ; Ошибка ввода!
msgErrorr db "Error! There is no such character in the string!", 0 ; Ошибка ввода!
msgErrorrr db "Error! Please enter only one character!", 0 ; Ошибка ввода!
msgFinal db CRLF, "Enter any char and press 'Enter' for exit", CRLF, 0; инструкция по выходу из программы
formatInt db '%d',0 ; описание формата целого числа
formatStr db '%s',0 ; описание формата строки
.data? ; сегмент данных размещаемых в памяти динамически
cmpChar db ? ; переменная для хранения символа, с которым будет осуществляться сравнение
cmpCharr db ? ; переменная для хранения символа, с которым будет осуществляться сравнение
.code ; сегмент кода
start:
invoke crt_printf, ADDR formatStr, ADDR cmpStrComment ; выводим пояснение к сравниваемой строке...
invoke crt_printf, ADDR formatStr, ADDR cmpStr ; ... и саму строку
;______________________________________
thesame: ; метка для повторного ввода при одинаковых символах
invoke crt_printf, ADDR formatStr, ADDR msgInviteInput ; Приглашаем ввести 1 символ для сравнения...
invoke crt_scanf, ADDR formatStr, ADDR cmpChar ; ... и считываем его
invoke crt_printf, ADDR formatStr, ADDR msgInviteInputt ; Приглашаем ввести 2 символ для сравнения...
invoke crt_scanf, ADDR formatStr, ADDR cmpCharr ; ... и считываем его
mov al, cmpChar ; Первый символ
cmp al, cmpCharr ; Проверка на одинаковые символы
jl EndPr ; <
jg EndPr ; >
jz errr ; =
errr: ; если символы совпадают
invoke crt_printf, ADDR formatStr, ADDR msgError ; сообщение об ошибке "Одинаковые символы"
JMP thesame ; повторный ввод
EndPr:
;____________________________________________________________________________________________________________________
mov edi, offset cmpStr ; запоминаем адрес начала строки для сравнения
mov ecx, offset cmpStrComment ; сохраняем адрес начала переменной, объявленной после строки в которой осуществляется поиск
sub ecx, edi ; вычитаем из него ^ адрес начала строки для сравнения и получаем её длину
sub ecx, 1 ; так как последний символ, означающий конец строки, нам не нужем, уменьшаем длину на 1
xor ebx, ebx ; обнуляем регистр ebx, в нём будет храниться искомое число
cld ; сбрасываем флаг для инкримента регистра edi в scas далее
lp1: ; начало цикла подсчёта количества удвлетворящих условиям символов в строке
scasb ; сравниваем текущий символ (байт, на который указывает es:edi) с символом в al
jz skip ; = выходим из цикла
inc ebx ; счетчик до первой позиции
loop lp1 ; цикл отработает количество раз, равное длине строки, сохранённой в ecx ранее
skip: ; метка для выхода
cmp ebx, 18 ; Проверка на наличие такого символа, 18 тк пользователь не может сам менять строку!
jl EndPrr ; <
jg EndPrr ; >
jz err ; =
err: ; если символы совпадают
invoke crt_printf, ADDR formatStr, ADDR msgErrorr ; сообщение об ошибке "нет такого символа"
JMP thesame ; повторный ввод
EndPrr:
mov esi, ebx
mov al, cmpCharr
mov edi, offset cmpStr ; запоминаем адрес начала строки для сравнения
mov ecx, offset cmpStrComment ; сохраняем адрес начала переменной, объявленной после строки в которой осуществляется поиск
sub ecx, edi ; вычитаем из него ^ адрес начала строки для сравнения и получаем её длину
sub ecx, 1 ; так как последний символ, означающий конец строки, нам не нужем, уменьшаем длину на 1
xor ebx, ebx ; обнуляем регистр ebx, в нём будет храниться искомое число
cld ; сбрасываем флаг для инкримента регистра edi в scas далее
lp2: ; начало цикла подсчёта количества удвлетворящих условиям символов в строке
scasb ; сравниваем текущий символ (байт, на который указывает es:edi) с символом в al
jz skipp ; = выходим из цикла
inc ebx ; счетчик до первой позиции
loop lp2 ; цикл отработает количество раз, равное длине строки, сохранённой в ecx ранее
skipp: ; метка для выхода
cmp ebx, 18 ; Проверка на наличие такого символа, 18 тк пользователь не может сам менять строку!
jl EndPrrr ; <
jg EndPrrr ; >
jz erro ; =
erro: ; если символы совпадают
invoke crt_printf, ADDR formatStr, ADDR msgErrorr ; сообщение об ошибке "нет такого символа"
JMP thesame ; повторный ввод
EndPrrr:
; esi ; число символов до 1 числа
; ebx ; число символов до 2 числа
sub ebx, esi ; находим разницу-расстояние
sub ebx, 1
test ebx, ebx ; тест на знак числа ответа
JZ plus
js minys
plus:
JMP EndProg
minys:
neg ebx ; если результат отрицательный
JMP EndProg
EndProg:
invoke crt_printf, ADDR formatStr, ADDR msgRes ; выводим пояснение о результате
invoke crt_printf, ADDR formatInt, ebx ; выводим результат
invoke crt_printf, ADDR formatStr, ADDR msgFinal ; объясняем, как выйти из программы
invoke crt_scanf, ADDR formatStr, ADDR cmpChar ; переиспользуем переменную для хранения ненужных данных
invoke ExitProcess, 0 ; закрываем программу, возвращаемся к ОС
end start ; выполнение программы начнётся с метки start