Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- .386
- .MODEL FLAT, STDCALL ; Определяем модель памяти
- OPTION CASEMAP: NONE ; Опции компилятора
- ; Объявление внешних функций из библиотеки kernel32.dll
- EXTERN WriteConsoleA@20: PROC ; Функция для вывода строки в консоль
- EXTERN CharToOemA@8: PROC ; Функция для преобразования кодировки строки в DOS
- EXTERN GetStdHandle@4: PROC ; Функция для получения хэндла устройства ввода/вывода
- EXTERN lstrlenA@4: PROC ; Функция для определения длины строки
- EXTERN ExitProcess@4: PROC ; Функция для завершения процесса
- EXTERN ReadConsoleA@20: PROC ; Функция для считывания строки с консоли
- ; Секция данных
- .DATA
- ; Строки для вывода
- STR1 DB "Введите 1 число: ", 10, 0 ; Строка с приглашением для ввода первого числа
- STR2 DB "Введите 2 число: ", 10, 0 ; Строка с приглашением для ввода второго числа
- STR3 DB "Результат: ", 0 ; Строка для вывода результата
- ERROR_STR DB "Произошла ошибка, введенное число должно быть от 3 до 8 символов!", 0 ; Строка с сообщением об ошибке при вводе числа неверной длины
- OVERFLOW DB "Произошла ошибка переполнения регистра, невозможно определить результат произведения", 0 ; Строка с сообщением об ошибке при переполнении регистра в процессе умножения
- ; Переменные для хранения данных
- DOUT DD ? ; Хэндл для вывода в консоль
- DIN DD ? ; Хэндл для ввода с консоли
- LENS DD ? ; Переменная для хранения длины введенной строки
- NUM1 DD ? ; Переменная для хранения первого числа
- NUM2 DD ? ; Переменная для хранения второго числа
- BUF DB 20 dup (?) ; Буфер для временного хранения введенных строк
- OS DD ? ; Коэффициент для вычислений
- S_10 DD 10 ; Константа для конвертации числа из восьмеричной системы в десятичную
- SIGN_FIRST DB ? ; Флаг знака первого числа (0 - положительное, 1 - отрицательное)
- SIGN_SECOND DB ? ; Флаг знака второго числа (0 - положительное, 1 - отрицательное)
- SIGN DB ? ; Флаг знака результата (0 - положительный, 1 - отрицательный)
- ; Секция кода
- .CODE
- MAIN PROC
- ; Изменяем кодировку строк на 'досовскую'
- MOV EAX, OFFSET STR1
- PUSH EAX
- PUSH EAX
- CALL CharToOemA@8 ; Преобразование кодировки первой строки
- MOV EAX, OFFSET STR2
- PUSH EAX
- PUSH EAX
- CALL CharToOemA@8 ; Преобразование кодировки второй строки
- MOV EAX, OFFSET STR3
- PUSH EAX
- PUSH EAX
- CALL CharToOemA@8 ; Преобразование кодировки третьей строки
- MOV EAX, OFFSET ERROR_STR
- PUSH EAX
- PUSH EAX
- CALL CharToOemA@8 ; Преобразование кодировки строки с сообщением об ошибке
- MOV EAX, OFFSET OVERFLOW
- PUSH EAX
- PUSH EAX
- CALL CharToOemA@8 ; Преобразование кодировки строки с сообщением о переполнении
- ; Получаем хэндлы для вывода и ввода
- PUSH -11
- CALL GetStdHandle@4
- MOV DOUT, EAX ; Получение хэндла для вывода
- PUSH -10
- CALL GetStdHandle@4
- MOV DIN, EAX ; Получение хэндла для ввода
- ; Выводим приглашение для ввода первого числа
- ; Загружаем указатель на строку STR1 в регистр EAX
- PUSH OFFSET STR1
- ; Вызываем функцию lstrlenA для определения длины строки
- CALL lstrlenA@4
- ; Подготавливаем параметры для вызова WriteConsoleA@20
- PUSH 0
- PUSH OFFSET LENS
- PUSH EAX
- PUSH OFFSET STR1
- PUSH DOUT
- ; Вызываем функцию WriteConsoleA для вывода строки в консоль
- CALL WriteConsoleA@20
- ; Считывание первого числа из консоли
- ; Подготавливаем параметры для вызова ReadConsoleA@20
- PUSH 0
- PUSH OFFSET LENS
- PUSH 200
- PUSH OFFSET BUF
- PUSH DIN
- ; Вызываем функцию ReadConsoleA для считывания строки с консоли
- CALL ReadConsoleA@20
- ; Преобразование первого числа из строки символов в число
- MOV ESI, OFFSET BUF
- DEC LENS
- DEC LENS
- MOV ECX, LENS
- MOV AL, [ESI] ; Проверяем первое число на отрицательность
- CMP AL, '-'
- JNE CONTINUE_F ; Если первый символ не -, то продолжаем переводить число из строки
- DEC LENS ; Если первый знак -, то уменьшаем длину строки на 1
- MOV ECX, LENS
- INC ESI ; Перемещаем регистр ESI на 1 вперед (на первую цифру числа)
- MOV SIGN_FIRST, 1 ; Меняем знак первого числа на -
- CONTINUE_F: ; Продолжаем переводить число
- CMP LENS, 3
- JB ERROR
- CMP LENS, 8
- JA ERROR
- MOV OS, 8
- XOR EAX, EAX
- XOR EBX, EBX
- CONV:
- MOV BL, [ESI]
- SUB BL, 48
- MUL OS
- ADD EAX, EBX
- INC ESI
- LOOP CONV
- MOV NUM1, EAX
- PUSH OFFSET STR2 ; Выводим приглашение для ввода второго числа
- CALL lstrlenA@4
- PUSH 0
- PUSH OFFSET LENS
- PUSH EAX
- PUSH OFFSET STR2
- PUSH DOUT
- CALL WriteConsoleA@20 ; Выводим приглашение для ввода второго числа в консоль
- ; считывание второго числа из консоли
- PUSH 0
- PUSH OFFSET LENS
- PUSH 200
- PUSH OFFSET BUF
- PUSH DIN
- CALL ReadConsoleA@20
- ; Преобразование второго числа из сторки символов в число
- MOV ESI, OFFSET BUF
- DEC LENS
- DEC LENS
- MOV ECX, LENS
- MOV AL, [ESI] ; Проверяем второе число на отрицательность
- CMP AL, '-'
- JNE CONTINUE_S ; Если первый символ числа не минус, то продолжаем конверитровать число
- DEC LENS ; Если минус, то уменьшаем длину строки на 1
- MOV ECX, LENS
- INC ESI ; Сдвигаем регистр ESI на одни (чтобы указывал на число)
- MOV SIGN_SECOND, 1 ; меняем знак числа на -
- CONTINUE_S: ; Продолжаем переводить число
- CMP LENS, 3
- JB ERROR
- CMP LENS, 8
- JA ERROR
- MOV OS, 8
- XOR AX, AX
- XOR BX, BX
- SONV:
- MOV BL, [ESI]
- SUB BL, 48
- MUL OS
- ADD AX, BX
- INC ESI
- LOOP SONV
- MOV NUM2, EAX
- ; Выводим строку с результатом
- PUSH OFFSET STR3
- CALL lstrlenA@4
- PUSH 0
- PUSH OFFSET LENS
- PUSH EAX
- PUSH OFFSET STR3
- PUSH DOUT
- CALL WriteConsoleA@20
- ; Проверяем какой должен быть знак у результата
- CMP SIGN_FIRST, 1
- JNE AGAIN
- CMP SIGN_SECOND, 0
- JNE AGAIN
- MOV SIGN, 1
- AGAIN:
- CMP SIGN_FIRST, 0
- JNE ALG
- CMP SIGN_SECOND, 1
- JNE ALG
- MOV SIGN, 1
- ALG:
- XOR EDX, EDX
- XOR EBX, EBX
- XOR EAX, EAX
- MOV EAX, NUM1
- MOV EBX, NUM2
- MUL EBX ; производим умножение введенных чисел
- JC OVER
- MOV EBX, EAX
- MOV ESI, OFFSET BUF
- CMP SIGN, 0 ; Если результат отрицательный, то добавить в строку знак '-'.
- JE FUNC
- MOV AX, 45 ; 45 - код знака '-'.
- MOV [ESI], AX
- INC ESI
- FUNC:
- MOV EAX, EBX ; Копируем значение EBX в EAX
- XOR EDX, EDX ; Обнуляем EDX (остаток от деления)
- XOR EDI, EDI ; Обнуляем EDI (счетчик цифр)
- CONVERT_FROM8TO10:
- CMP EBX, S_10 ; Сравниваем EBX с 10
- JAE FUNC1 ; Если EBX >= 10, переходим к FUNC1
- JB FUNC5 ; Если EBX < 10, переходим к FUNC5
- FUNC1:
- DIV S_10 ; Делим содержимое EAX на 10, результат в EAX, остаток в EDX
- ADD DX, '0' ; Прибавляем '0' к остатку, чтобы получить ASCII-код цифры
- CMP DX, '9' ; Сравниваем остаток с '9'
- JA FUNC2 ; Если остаток > '9', переходим к FUNC2
- JBE FUNC3 ; Если остаток <= '9', переходим к FUNC3
- FUNC2:
- ADD DX, 7 ; Добавляем 7 к остатку для преобразования в ASCII-код цифры
- FUNC3:
- PUSH EDX ; Кладем остаток в стек (для инвертирования)
- ADD EDI, 1 ; Увеличиваем счетчик цифр
- XOR EDX, EDX ; Обнуляем EDX
- XOR EBX, EBX ; Обнуляем EBX
- MOV BX, AX ; Переносим результат деления в BX (новое число для деления)
- MOV ECX, 2 ; Задаем значение ECX для цикла инвертирования
- LOOP CONVERT_FROM8TO10
- FUNC5:
- ADD AX, '0' ; Прибавляем '0' к результату для преобразования в ASCII-код
- CMP AX, '9' ; Сравниваем результат с '9'
- JA FUNC6 ; Если результат > '9', переходим к FUNC6
- JBE FUNC7 ; Если результат <= '9', переходим к FUNC7
- FUNC6:
- ADD AX, 7 ; Добавляем 7 к результату для преобразования в ASCII-код
- FUNC7:
- PUSH EAX ; Кладем результат в стек (для инвертирования)
- ADD EDI, 1 ; Увеличиваем счетчик цифр
- MOV ECX, EDI ; Переносим значение счетчика цифр в ECX
- CONVERTS:
- POP [ESI] ; Извлекаем значения из стека и записываем в буфер по адресу ESI
- INC ESI ; Увеличиваем ESI
- LOOP CONVERTS
- PUSH OFFSET BUF ; Кладем указатель на буфер в стек
- CALL lstrlenA@4 ; Получаем длину строки в буфере
- PUSH 0 ; Флаг для указания на ASCIIZ-строку
- PUSH OFFSET LENS ; Кладем указатель на переменную LENS в стек
- PUSH EAX ; Кладем длину строки в стек
- PUSH OFFSET BUF ; Кладем указатель на буфер в стек
- PUSH DOUT ; Кладем хэндл вывода в стек
- CALL WriteConsoleA@20 ; Вызываем функцию вывода строки в консоль
- PUSH 0 ; Код завершения процесса
- CALL ExitProcess@4 ; Завершаем программу
- PUSH 0 ; Резервируем место в стеке (заглушка)
- CALL ExitProcess@4 ; Вызываем функцию ExitProcess для завершения программы
- ERROR:
- PUSH OFFSET ERROR_STR; Помещаем в стек указатель на строку ERROR_STR
- CALL lstrlenA@4 ; Вызываем функцию lstrlenA для определения длины строки
- PUSH 0 ; Помещаем параметры для вызова функции WriteConsoleA@20 в стек
- PUSH OFFSET LENS
- PUSH EAX
- PUSH OFFSET ERROR_STR
- PUSH DOUT
- CALL WriteConsoleA@20 ; Вызываем функцию WriteConsoleA для вывода строки в консоль
- PUSH 0 ; Помещаем параметр для завершения процесса в стек
- CALL ExitProcess@4 ; Вызываем функцию ExitProcess для завершения программы
- OVER:
- ; Выводим сообщение об ошибке переполнения
- PUSH OFFSET OVERFLOW ; Помещаем в стек указатель на строку OVERFLOW
- CALL lstrlenA@4 ; Вызываем функцию lstrlenA@4 для определения длины строки
- PUSH 0 ; Помещаем параметры для вызова функции WriteConsoleA@20 в стек
- PUSH OFFSET LENS
- PUSH EAX
- PUSH OFFSET OVERFLOW
- PUSH DOUT
- CALL WriteConsoleA@20
- PUSH 0
- CALL ExitProcess@4
- MAIN ENDP
- END MAIN
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement