Предусмотрена работа как с положительными числами, так и с отрицательными.
ЗАКЛЮЧЕНИЕ
В курсовом проекте была разработана программа-калькулятор, реализующая выполнение четырех основных арифметических операций. Программа работоспособна и соответствует заявленным требованиям.
Программа может быть улучшена за счет расширения диапазонов входных данных. Также можно дополнить функционально: работа с числами в двоичном и шестнадцатеричном форматах. Доработкой может являться: увеличение числа операций над входными данными, например вычисление модуля числа, вычисление квадратного корня; работа с дробными значениями.
СПИСОК ЛИТЕРАТУРЫ
. Абель П., Язык ассемблера для IBM PC и программирования - М.: Высшая школа, 1992. - 447 с.
. Юров В.И., Assembler. Учебник для вузов. 2-е издание - СПБ.: Питер, 2003.- 638 с.
ПРИЛОЖЕНИЕ А. ЛИСТИНГ ПРОГРАММЫ
;17. Программа-калькулятор, позволяющая пользователю выполнять четыре основных
;арифметических действия над целыми числами, укладывающимися в 8-байтовый диапазон.
;--------------макросы----------------------
;----вывод строки---------------------------macro str;в str заносим адрес строки для выводаah, 09h;функция вывода 21го прерыванияdx, str;адрес строки в dx21h;вызов прерывания 21h
;----считывание знака операции--------------flag1, b08, b09string_1;макрос вывода строки "Введите число: "ax, ax;обнуляем регистрыdx, dxah, 01h;функция считывания символа с клавиатуры (с эхо)21h;вызов прерывания 21hal, '+';сравнение с '+' b09al, '-';сравнение с '-'b09b08;пока знак операции не будет введен игнорируем:di, flag1;запись знака в соотв место памяти знака[di], al
;----считывание строки в буфер--------------
;первый байт буфера должен содержать мах длину
;второй байт содержит факт длину по возвращению
_bmacro str;в str заносим адрес буфера для вводаah, 0Ah;функция считывание строки в буферdx, str;адрес буфера в dx21h;вызов прерывания 21hstring_5;макрос вывода строки (переноса каретки)
;----перенос в правую часть буфера----------
perepmacro buf, numb,a28,b23,b24
lea di, buf+1;перенос числа из буферной памятиcx, [di];в память, начиная с правого краяch,ch;необходимого отрезка памяти
add di, cxsi, numb+8
a28:ax, [di]al, byte ptr 29h;проверка на корректность вводимых данныхb23;переход, если ниже или равно
cmp al, byte ptr 40hb23;переход, если выше или равно
mov [si], axsidi
loop a28b24
b23:
print string_3;вывод строки "введен некорректный символ операции"
print string_5b111;начнем сначала
b24:
;----перемещение местами--------------------a00;меняем местами два числаdi, numbe_01+1;чтобы упростить алгоритм работы со знакамиsi, numbe_02+1;чтобы первое всегда было больше
mov cx, 8
a00:al, [di]bl, [si][si], al[di],bldisi
loop a00
;----установка знака ответа-----------------_flag macro f00, b07;запись в флаг того, что насчитали
lea di, flag03[di],byte ptr f00
jmp b07
;----работа с нулями (обрезка/проверка)-----
nuli macro a78,a69,a70
a69:;обрезаем лидирующие нули
mov al,[si]al, 00h;вдруг уже не ноль
jne a78si
loop a69
a78:;вдруг прописаны только нулиal,[si]al, 30ha70al, 00h;заменям нули на нули (30h на 00h)
mov [si], alsi
loop a78
endm
;----смещение разрядов внутри буфера--------macro b64, bx
b64:;смещаем разряды слева направоbxal, [bx];берем правыйbx[bx], al;перекладываем левееbx
loop b64
;----считывание символа операции------------_klmacrostring_2;макрос вывода строки "Выберете оперецию: "ax, ax;обнуляем регистрыdx, dxah, 01h;функция считывания символа с клавиатуры (с эхо)21h;вызов прерывания 21hal, '+';сравнение с '+' op_01;если равны - значит складываемal, '-';сравнение с '-'op_02;если равны - вычитаемal, '*';сравнение с '*'op_03;если равны - умножаемal, '/';сравнение с '/'op_04;если равны - делимal, 'q';сравнение с 'q'Quit;выходим из программыal, 'Q';сравнение с 'Q'Quit;выходим из программыmet_op;если введен другой символ, ;то игнорируем и ждем нового(снова в макрос)
;-------------------------------------------
;-------------------------------------------
.model small
.stack 100h
.data_1db0,13,'Enter the number: $'_2db0,13,'Select operation: $'_3db0,13,'Entered an incorrect number. Try again. $'_4db10,13,'Incorrect operation. a<b. Try again. $'_5db0Dh,0Ah,'$';перевод каретки_6db10,13,'Result operation: $'_7db10,13,'Incorrect operation. b=0. Try again. $'
;результат операции деления?_01dq8;первое число_01dq8;первое число, начиная с правого краяdw?_02dq8;второе число_02dq8;второе число, начиная с правого краяdw?_03dq8 ;буфер для выводаdw?_04dq8;буфер для деленияdw?_05dq2 dup (0);выделение памяти;если 1е меньше, то флаг равен 1db0;если результат вычитания 0, то флаг равен 1db0;знак 1го числа (2B='+', 2D='-')db0;знак 2го числаdb0;знак результата
.code:ax, @data;запись в ax адреса на сегмент данныхds, ax;инициализация сегмента данныхes, ax;инициализация сегмента доп. данных
clear;вызов процедуры очистки экрана
b111:di, numbe_01+1si, numbe_02+1och_bufer
di, bufer_03+1si, bufer_04+3och_bufer
di, chastnoesi, bufer_04+11och_bufer
b11:flag01, b11, b12;считываем знак 1го числа
read_b bufer_01;считываем строку в буфер_1
b13:flag02, b13, b14;считываем знак 2го числа_b bufer_02;считываем строку в буфер_2
bufer_01, numbe_01, a28, b23, b24;макрос переноса в правую часть 1го числаbufer_02, numbe_02, a29, b25, b26;макрос переноса в правую часть 2го числа
;сделаем, чтобы первое всегда было большеdi, numbe_01+2;первое числоsi, numbe_02+2;второе числоsrav;вызываем процедуру сравненияdx, [bx];проверка флага
cmp dl, byte ptr 00;a>b
je b00 b18;b>a
;необходимо помменять местами знакиdi, flag01;первое числоsi, flag02;второе число
mov bl, [si][di], bl [si], al
b00:;теперь всегда a>b_op:read_kl;макрос считывания символа операции
:ax, 4c00h;стандартное завершение программы21h
_01:;сложение с учетом знаковzp_znak
al, byte ptr 56h;оба числа положительные (2B+2B)b01al, byte ptr 5Ah;оба числа отрицательные (2D+2D)b02dl, byte ptr 2Bh;одно отрицательное (2D), второе (в dl первый знак. если он положительный, то переход)b03
;если 1й отрицательный, то переход на b04
b04:di, numbe_01+8;получаем адрес 1го числа, начиная с правого разряда
call p_vich;-a+b_flag 2Dh, b07
b01:call p_sloj;a+b_flag 2Bh, b07
b02:call p_sloj;-a+(-b)
set_flag 2Dh, b07
b03:lea di, numbe_01+8;получаем адрес 1го числа, начиная с правого разряда
call p_vich;a+(-b)_flag 2Bh, b07
b07:
lea bx, bufer_03;адрес на буфер в bxcallvivod_02:;вычитание с учетом знакаzp_znak
al, byte ptr 56h;оба числа положительные (2B+2B)b03al, byte ptr 5Ah;оба числа отрицательные (2D+2D)b04dl, byte ptr 2Bh;одно отрицательное (2D), второеb01b02;одно отрицательное, первое
op_04: jmp op_042_03:zp_znak
cmp al, byte ptr 58h;числа с разным знаком (2D+2B)b06_flag 2Bh, b05;знак вывода +
b06: _flag 2Dh, b05;знак вывода -;умножение
b05:call p_umno;вызов процедуры умножения
jmp callvivod2_042:zp_znak
cmp al, byte ptr 58h;числа с разным знаком (2D+2B)b16_flag 2Bh, b17;знак вывода +
b16: _flag 2Dh, b17;знак вывода -;деление
b17:call p_dele;вызов процедуры умноженияbx, chastnoe;адрес на буфер в bx
;jmp callvivodпереходим:;вывод после сложения+вычитанияstring_6;макрос вывода строки "Результат операции: "vivod;процедура вывода числа из bufer_03string_5;макрос вывода строки (переноса каретки)b111:;вывод после умноженияstring_6;макрос вывода строки "Результат операции: "vivod2;процедура вывода числа из bufer_04string_5;макрос вывода строки (переноса каретки)b111
;
;теперь необходимо обнулить ячейки в памяти (буферы 1,2,3) - скорее всего процедурой
;и прыгнуть на метку, которая после вызова процедуры очистки экрана
;--------------процедуры--------------------
;----процедура очистки экрана---------------proc ah, 00h;установка видеорежима дисплеяal, 03h;номер видеорежима10h;вызов прерывания 10hendp
;----сравнение чисел а и б------------------
sravproccx, 7bx, flag[bx], byte ptr 00;обнуляем значение флага
a35:al, [di]al, [si]
jg a36;если 1е больше, то переходa37;если равны
;lea bx, flag
mov [bx], byte ptr 01a36;на выход
a37:disi
loop a35
a36:endp
;----процедура записи знаков----------------
zp_znakprocdi, flag01si, flag02 al, [di]dl, al;сохраним знак 1го числа
add al, [si]_znak endp
;----очистка буферов------------------------_bufer proccx, 8
b20:[di], byte ptr 00[si], byte ptr 00disi
loop b20_bufer endp
;----сложение-------------------------------
p_sloj proc
clc;очистка флага переносаdi, numbe_01+8;получаем адрес 1го числа, начиная с правого разрядаsi, numbe_02+8;получаем адрес 2го числа, начиная с правого разрядаbx, bufer_03+8;получаем адрес, по которому запишем результат, начиная с правого разрядаcx, 7;в счетчик заносим длину числа в байтах
a20:ax, ax;очистим регистр AHal, [di];загрузим ASCII-байтal, [si] ;сложение (с переносом);коррекция для ASCII[bx], al;сохранение суммыbx[bx], ah;добавляем перенос
dec sidi
loop a20;зациклим
mov [bx], ah;сохраним перенос
p_sloj endp
;----вычитание------------------------------_vich proc
clc;очистка флага переносаbx, bufer_03+8;получаем адрес, по которому запишем результат, начиная с правого разрядаsi, numbe_02+8;получаем адрес 2го числа, начиная с правого разрядаcx, 7;в счетчик заносим длину числа в байтах
a22:ah, 00;очистим регистр AHal, [di];загрузим ASCII-байтal, [si] ;вычитание (с заемом);коррекция для ASCII[bx], al;сохранение суммы
dec sidibx
loop a22;зациклим[bx], ah;сохраним перенос
ret_vich endp
;----умножение------------------------------
p_umno procbx, numbe_02+8;записываем множитель в bx cx, 7;количество циклов для умножения__________________сделать более динамичным (для исходного числа символов)(дальше еще цикл=))
a24:;цикл призванный менять числа-множители (те цифры во втором буфере)si, numbe_01+8;получаем адрес 1го числа - множимоеdi, bufer_04+8;получим адрес на буфер необходимый для хранения промежуточного результата (эти результаты суммируем со сдвигом)di, cx;увеличиваем di, ччтобы не сползало (сдвиг)
mov al, [bx]ah, ahal, 0fh;образаем тройкуdl, al
push cx;сохраняем в стеке счетчик, отвечающий за изменяемое число множителяcx, 7
a23:al, [si];загружаем ascii-символ из 1го буфераah, ahal, 0fh;отнимаем тритцаткуdl;результат операции в ax;коррекция для asciial, [di];коррекция для ASCII[di], al;запись в память младшей частиdi;для записи переносаal, ahah, ahal, [di];запись в память старшей части[di], aldi;сохраняем в стек di
a40:;расчет переносаah, 00h;тк в нам необх в 10ой, то переносим все лишнееa39;переходим если нет переноса в самый конец
dec dial, ahah, ahal, [di][di], ala40
a39:ax,ax si
pop di;забираем из стека di
loop a23cxbx
;----деление--------------------------------_dele proc dx, dx;счетчик, необходим далееdxdi, numbe_01+1;первое число ооооххххsi, numbe_02+1;второе число ооооххххcx, 8
nuli a78,a69,a70;макрос проверки, на 00 и 30hstring_7;делитель нулевой, выходим (некорекктные данные, b равно 0)string_5;макрос вывода строки (переноса каретки)
ret
a70:di, numbe_01;первое число ооооххххsi, numbe_02
call srav;процедура сравнения двух чиселdx, [bx];проверка флага dl, byte ptr 01;флаг - 1? тогда выходимa68;не равно 1, 1е больше, значит выполняем делениеstring_4;макрос вывода строки (некорректная операция)string_5;макрос вывода строки (переноса каретки)
a68:
;----сравнение чисел поразрядно
;сравнение 1го разряда делимого с делителемdi, numbe_01+2;первое число ооооххххbx, bufer_04+8;часть первого числаal, [di];записываем в al крайний левый разряд первого числа[bx], al;хаписываем в [bx] в крайнюю правую позицию
a73:di, bufer_04+2;первое числоsi, numbe_02+2;второе числоsrav;процедура сравнения двух чиселdx, [bx];проверка флага dl, byte ptr 01;флаг - 1? тогда выходимa63;не равно 1, 1е больше, значит начинаем вычитать
;----1е меньше, то плюсуем еще число в bx из di
;---сдвиг частного [bx] внутри буфера
a65:bx, bufer_04+2
mov cx, 6;по итогам последний разряд делаем предпоследним разрядом
jmp a64: jmp a70
a64:
smesh a64, bx;макрос смещения строки
;запись левого разряда di в правый разряд bxdxdx;какой по счету разряд делимого переносим в "часть делимого"dx;счетчикdi, numbe_01+2;изначальное частное (начнем со второго, тк первое уже юзаем) - таким же сдвигом пользуемся!!!di, dx;прибавляем к адресу смещение из счетчика
bx, bufer_04+8;в правый разряд записываем новый разряд
lea si, flag2al, [di][bx], al
al, 30h;новый разряд 0?
jnz a99;если не ноль, то продолжаем считатьcx, [si]cl, byte ptr 01;если флаг 0, то результат вычитание ненулевой, прод считатьa99
di, chastnoe+2;запись в последний разряд нового разряда частного
mov cx, 7;по итогам последний разряд заполнен мусоромdl, dla61 ;счетчик для частного ноль и запишем его в конец
a99:[si],byte ptr 00;обнулим флаг2si, bufer_04+2
mov cx, 7
a90:dx, 7a73dx;достаем лишнее из стека;закончили деление, выходим из процы деления
a63:
;----если делимое [bx] больше делителя [si], то вычитаем пока это условие верно-----------dx, dx;обнуляем и далее используем как счетчик
a67:di, bufer_04+8;1й параметр, необходимый для процедурыp_vich;ВЫЧИТАНИЕdx;в качестве счетчика (увеличение частного) используем dxdx
;----перемещаем результат из bufer_03 в bufer_04------
lea di, bufer_03+2si, bufer_04+2cx, 7
a66:al, [di] al, 30h;добавим тройку!
mov [si], al[di], byte ptr 00;очищаем bufer_03+1disi
loop a66
lea si, bufer_04+2;стираем лидирующие нули
mov cx, 7
a74:al, [si]
cmp al, 30h;сравниваем с нулемa75;если не ноль, то выводим[si], byte ptr 00;очищаем bufer_03+1
inc disi
loop a74
a75:cx,0000h;значит стирали лидирующие нули до предела=>все нулиa98si, flag2[si], byte ptr 01;установка флага, если результат вычитания 0
a98:
;-----------------------------------------------------
;----сравниваем после вычитание, делимое больше?------di, bufer_04+2;первое числоsi, numbe_02+2;второе числоsrav;процедура сравнения двух чиселdx, [bx];проверка флага dl, byte ptr 01;флаг - 1? тогда выходимdx
;----да! больше! вычитаем еще раз---------------------a67;если флаг=0, 1е больше, повторяем вычитание
;----если bx меньше, то сдвигаем и приписываем в частное [di] из dl(счетчик), также записываем частное и сдвигаемdi, chastnoe+2;запись в последний разряд нового разряда частного
mov cx, 7;по итогам последний разряд заполнен мусором
a61:
a61, didi, chastnoe+8;запись в последний разряд нового разряда частного
mov [di], dldl, dl
jmp a65_dele endp
;----вывод результата-----------------------
vivod procdi, flag03ah, 02h dl, [di]21hbx;1й байт - не интересуетcx, 8;счетчик чисел
a26:;стираем лидирующие нулиbyte ptr[bx], 00h;сравниваем с нулемa21;если не ноль, то выводимbyte ptr[bx], 20h;если ноль, заменяем пробелом bx
loop a26cl, byte ptr 00h;продолжаем уменьшать счетчикa21bx, bufer_03+3;адрес на буфер в bxcx, 1
a21:[bx], 3030h;для вывода в 10ом форматеah, 02h;функция вывода символаdl, [bx];в dl выводимый символ21h;вызов прерывания 21hbx;следующая ячейка
loop a21;зациклимendp
;----вывод результата-умножения--------------
vivod2 proc
lea di, flag03
mov ah, 02hdl, [di] 21h
lea bx, bufer_04+3;адрес на буфер в bxcx, 13;счетчик чисел
a33:;стираем лидирующие нулиbyte ptr[bx], 00h;сравниваем с нулемa21;если не ноль, то выводимbyte ptr[bx], 20h;если ноль, заменяем пробелом bx
loop a33cl, byte ptr 00h;продолжаем уменьшать счетчикa25bx, bufer_04+3;адрес на буфер в bxcx, 1
a25:[bx], 3030h;для вывода в 10ом форматеah, 02h;функция вывода символаdl, [bx];в dl выводимый символ21h;вызов прерывания 21hbx;следующая ячейка
loop a25;зациклимendp
;-------------------------------------------start