Интересный калькулятор на 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
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д