Добавил:
БГУИР ПОИТ Дистанционное Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Часть 1 / ИПР1_В5 / Отчет ИПР1

.docx
Скачиваний:
10
Добавлен:
06.10.2021
Размер:
41.75 Кб
Скачать

БЕЛОРУССКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ

ИНФОРМАТИКИ И РАДИОЭЛЕКТРОНИКИ

Кафедра программного обеспечения информационных технологий

Факультет ФКСиС

Специальность ПОИТ

Индивидуальная практическая работа № 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

Соседние файлы в папке ИПР1_В5