Интересный калькулятор на TASM - Assembler
Формулировка задачи:
Всем доброго времени суток. Такой вопрос: есть калькулятор, который выполняет 4 простейших арифметических операций с двумя числами. Задача заключается в том чтобы его немного модифицировать и упростить согласно тз: написать калькулятор, выполняющий над двумя знаковыми числами размером в слово следующие операции: нахождение максимального, минимального и среднего арифметического значений (все отдельно, можно через процедуры) ну и вывод их на экран соответственно.
Заранее спасибо!
.model tiny ;COM - файл
.code
.386 ;используем eax
org 100h
start:
vvod1: ;выбор функции
xor eax,eax ;обнуляем регистры
xor edx,edx ;
call clrscr
mov ah,9 ;Вывод сторки мессаге1
mov dx,offset message1 ;
int 21h ;
mov ah,08h ;считать символ с клавиатуры
int 21h ;
cmp al,'+' ;сравнение с '+'
je cloj ;значит складываем
cmp al,'-'
je vich ;вычитание
cmp al,'/'
je dele ;деление
cmp al,'*'
je rr1 ;используем jmp т.к далеко
jmp rr ;
rr1: jmp umnoj ;Умножение
rr: cmp al,'q' ;выход
je quit
cmp al,'Q'
je quit
jmp short vvod1 ;если не ввели то повторять ввод
quit:
ret ;Выход
cloj: ;Сложение dx+ax->ax
call clrscr ;стереть экран
call aa1 ;ввод а
push dx ;сохраняем dx в стеке
call bb1 ;ввод b
pop dx ;вытаскиваем dx из стека
add ax,dx ;складываем ax и dx результат в eax
call print
call endstrd
mov ah,9 ;Вывод сторки мессаге2
mov dx,offset message2 ;
int 21h
mov ah,08h
int 21h ;
jmp vvod1
vich: ;вычитание
call clrscr ;стереть экран
call aa1 ;ввод а
push dx
call bb1 ;ввод b
pop dx
sub dx,ax ;вычитаем из dx ax результат в edx
mov ax,dx ;переносим его eax
call print ;выводит eax в десятичной системе
call endstrd
mov ah,9 ;Вывод сторки мессаге2
mov dx,offset message2 ;
int 21h
mov ah,08h
int 21h ;
jmp vvod1
dele: ;деление (цело численное)
call clrscr ;стереть экран
call aa1 ;ввод а
push dx
call bb1 ;ввод b
pop dx
xchg dx,ax
mov cx,dx ;сохраняем делитель в cx
xor dx,dx ;обнуляем dx там будет остаток
div cx ;делим результат в eax
call print
call endstrd
mov ah,9 ;Вывод сторки мессаге2
mov dx,offset message2 ;
int 21h
mov ah,08h
int 21h ;
jmp vvod1
umnoj: ;умножение
call clrscr ;стереть экран
call aa1 ;ввод а
push dx
call bb1 ;ввод b
pop dx
mul edx ;умножаем результат в eax
call print
call endstrd
mov ah,9 ;Вывод сторки мессаге2
mov dx,offset message2 ;
int 21h
mov ah,08h
int 21h ;
jmp vvod1
clrscr:
xor dx,dx ;положение курсора dh-строка dl-столбец
mov ah,02h ;установить в 0,0
int 10h ;
mov bl,0000111b ;атрибут символов белый на чёрном
mov cx,25*80 ;количество символов
mov ax,0920h ;вывод 25*80 пробелов
int 10h ;
ret
endp
aa1: ;ввод а
mov dx,offset aaaa
mov ah,9
int 21h
call mover
mov dx,ax ;перенесём в dx
ret
endp
bb1: ;ввод а
mov dx,offset bbbb
mov ah,9
int 21h
call mover
ret
endp
mover:
mov dx,offset bufer ;аресс буфера
mov ah,0ah ;считать строку данных в буфер
int 21h ;
mov dx,offset endstr ;перенос курсора на строку ниже
mov ah,9 ;
int 21h ;
;перевод из строки в бинарное число
xor di,di ;начало буферв
xor ax,ax ;текущее значение ax
mov cl,blength
xor ch,ch
xor bx,bx
mov si,cx ;длинна буфера
mov cl,10 ;множитель
tohex:
mov bl,byte ptr bconteg[di]
sub bl,'0' ;цифра = код символа - код символа '0'
jb tata ;если ко символа < чем код '0'
cmp bl,9 ;или > чем '9'
ja tata ;начать ввод занаво
mul cx ;иначе умножить на 10
add ax,bx ;добавить к ax новую цифру
inc di ;увеличить адресс
cmp di,si ;если он меньше чем кол. символов + 1
jb tohex
jmp tra
tata: jmp vvod1 ;Нужно использовать дальний переход
tra: ret
endp
print:
mov ebx,0ah ;делитель
xor cx,cx ;счётчик
divloop:
xor edx,edx ;обнуляем edx
div ebx ;делим на 10
add edx,'0' ;дописываем к остатку деления код нуля
push edx ;сохраняем число в стеке
inc cx ;увеличиваем счётчик на 1
test eax,eax ;если есть что делить то
jnz divloop ;продолжаем делить(если не ноль)
restore:
pop eax ;читаем записанные числа из стека
mov edx,eax ;пишем их в eax
mov ah,2 ;функция вывода символа по коду код в al
int 21h ;
dec cx ;уменьшаем счетчик
cmp cx,0 ;если он не = нолю
jne restore ;то проолжаем вывод
ret
endp
endstrd:
mov dx,offset endstr ;перенос курсора на строку ниже
mov ah,9 ;
int 21h ;
ret
endp
ret
message1 db "PRESS",0dh,0ah
db "+ for add. a+b.",0dh,0ah
db "- for sub. a-b",0dh,0ah
db "/ for div. a/b",0dh,0ah
db "* for mul. a*b",0dh,0ah
db "q for quit",0dh,0ah,'$'
message2 db "Press any key",0dh,0ah,'$'
aaaa db "a=",'$'
bbbb db "b=",'$'
endstr db 0dh,0ah,'$'
enderes db ' ',0dh,0ah,'$'
bufer db 5 ;max размер ввода чисел
blength db ? ;размер буфера после считывания
bconteg: ;содержимое буфера будет за концом файла
hexstring equ bconteg
end startРешение задачи: «Интересный калькулятор на TASM»
textual
Листинг программы
LOCALS ;разрешение одинаковых локальных меток (начинающихся с @@) .model tiny ;COM - файл .code .386 ;используем eax org 100h start: vvod1: ;выбор функции call clrscr mov ah,9 ;Вывод сторки мессаге1 mov dx,offset message1 ; int 21h ; mov ah,08h ;считать символ с клавиатуры int 21h ; Case1: cmp al,'m' ;сравнение с '+' jne Case2 call EnterAB call Min ;значит возвращаем минимум call ShowResult jmp vvod1 Case2: cmp al,'M' jne Case3 call EnterAB call Max ;значит возвращаем максимум call ShowResult jmp vvod1 Case3: cmp al,'a' jne Case4 call EnterAB call Average ;значит возвращаем среднее арифметическое call ShowResult jmp vvod1 Case4: cmp al,'q' ;выход je quit cmp al,'Q' je quit jmp short vvod1 ;если не ввели то повторять ввод quit: int 20h ;Выход ;Минимальное число ;на входе: ; ax - первое число ; bx - второе число ;на выходе: ; ax - минимальное из двух чисел Min proc cmp ax,bx jle @@Skip mov ax,bx @@Skip: ret Min endp ;Максимальное число ;на входе: ; ax - первое число ; bx - второе число ;на выходе: ; ax - максимальное из двух чисел Max proc cmp ax,bx jge @@Skip mov ax,bx @@Skip: ret Max endp ;Максимальное число ;на входе: ; ax - первое число ; bx - второе число ;на выходе: ; ax - максимальное из двух чисел Average proc add ax,bx ;складываем ax и bx результат в ax sar ax,1 ;делим на 2 при помощи арифметического сдвига ret Average endp ;ввод двух чисел для дальнейших вычислений ;на входе: ; - ;на выходе: ;ax - число A ;bx - число B EnterAB proc call clrscr @@ReadA: mov dx,offset aaaa mov ah,9 int 21h mov ah, 0Ah lea dx, bufer int 21h lea si, bufer+1 call Str2Num jc @@ReadA push ax call newstr @@ReadB: mov dx,offset bbbb mov ah,9 int 21h mov ah, 0Ah lea dx, bufer int 21h lea si, bufer+1 call Str2Num jc @@ReadB push ax call newstr pop bx pop ax ret EnterAB endp ;вывод строки результата и ожидание нажатия клавиши ;на входе ;ax - знаковое число для вывода в качестве результата ShowResult proc call Show_AX call NewStr mov ah,9 mov dx,offset message2 ; int 21h mov ah,08h int 21h mov ah, 06h ;считываем второй символ при нажатии функциональной клавиши mov dl, 0FFh int 21h ret ShowResult endp ; преобразования строки в число ; на входе: ; ds:[si] - строка с числом ; на выходе ; ax - число ; CY - флаг переноса (при ошибке - установлен, иначе - сброшен) Str2Num PROC LOCAL R: word pusha push ds push es push ds pop es mov cl, ds:[si] xor ch, ch jcxz @@Error push si ;для дальнейшей проверки знака inc si mov bx, 10 xor ax, ax ;если в строке первый символ '-' ; - перейти к следующему ; - уменьшить количество рассматриваемых символов cmp byte ptr [si], '-' jne @@Loop inc si dec cx @@Loop: mul bx ; умножаем ax на 10 ( dx:ax=ax*bx ) mov [di], ax ; игнорируем старшее слово cmp dx, 0 ; проверяем, результат на переполнение jnz @@ErrorWithPopSI mov al, [si] ; Преобразуем следующий символ в число cmp al, '0' jb @@ErrorWithPopSI cmp al, '9' ja @@ErrorWithPopSI sub al, '0' xor ah, ah add ax, [di] jc @@ErrorWithPopSI ; Если сумма больше 65535 cmp ax, 8000h ja @@ErrorWithPopSI inc si loop @@Loop pop si ;проверка на знак inc si cmp byte ptr [si], '-' jne @@Check ;если должно быть положительным neg ax ;если должно быть отрицательным jmp @@StoreRes @@Check: ;дополнительная проверка, когда при вводе положительного числа получили отрицательное or ax, ax ; js @@Error @@StoreRes: ;сохранить результат mov R, ax clc pop es pop ds popa mov ax, R ret @@ErrorWithPopSI: pop si @@Error: xor ax, ax mov R, ax stc pop es pop ds popa mov ax, R ret Str2Num ENDP ; выводит число из регистра AX на экран ; входные данные: ; ax - число для отображения Show_AX proc push ax push bx push cx push dx push di mov cx, 10 ; cx - основание системы счисления xor di, di ; di - кол. цифр в числе ; если число в ax отрицательное, то ;1) напечатать '-' ;2) сделать ax положительным or ax, ax jns @@Conv push ax mov dx, '-' mov ah, 2 ; ah - функция вывода символа на экран int 21h pop ax neg ax @@Conv: xor dx, dx div cx ; dl = num mod 10 add dl, '0' ; перевод в символьный формат inc di push dx ; складываем в стэк or ax, ax jnz @@Conv ; выводим из стека на экран @@Show: pop dx ; dl = очередной символ mov ah, 2 ; ah - функция вывода символа на экран int 21h dec di ; повторяем пока di<>0 jnz @@Show pop di pop dx pop cx pop bx pop ax ret Show_AX endp clrscr proc pusha mov ax, 0700h ;функция SCROLL DOWN ;mov al, 10 ;число пустых строк, вдвигаемых сверху (0=очистить все окно) mov bh, 07h ;атрибут для заполнения mov cx, 0000h ;верхний левый угол окна (считая от 0) mov dx, 24*256+79 ;нижний правый угол окна (считая от 0) int 10h mov ah, 0Fh ;читать текущий видеорежим int 10h mov ah, 02h ;установить курсор в левый верхний угол mov dx, 0000h ;левый верхний угол int 10h popa ret clrscr endp newstr proc pusha mov ah, 09h lea dx, endstr int 21h popa ret newstr endp ;------------------------------------------------------------ message1 db "PRESS",0dh,0ah db "m for min(a,b).",0dh,0ah db "M for max(a,b)",0dh,0ah db "a for (a+b)/2",0dh,0ah db "q for quit",0dh,0ah,'$' message2 db "Press any key",0dh,0ah,'$' aaaa db "a=",'$' bbbb db "b=",'$' endstr db 0dh,0ah,'$' enderes db ' ',0dh,0ah,'$' bufer db 5 ;max размер ввода чисел blength db ? ;размер буфера после считывания bconteg: ;содержимое буфера будет за концом файла end start