Найти значение выражения. Не получается вывести результат на экран - Assembler
Формулировка задачи:
Добрый вечер!
Помогите найти ошибку. Ассемблер изучаю всего несколько дней. Необходимо вычислить значение выражения (A*X+B)div(C*X*X+D*X+E). Ввод данных получилось сделать по образцу при помощи процедур ASCII, а как делать вывод на экран пока не понимаю, возможно ошибка где-то в вычислениях. Компилятор TASM 4.1 через DOSBox 0.74.
Заранее спасибо!
.model tiny ; модель (64 Кб) памяти, используемая для СОМ
.code ; начало сегмента кода
org 100h ; начальное значение счетчика инструкций (IP) - 100h
start: ; метка начала программы, расположена по адресу 100h
mov a,ax ; сохранение результата
mov ah,9 ; номер функции вывода на экран - в АН
mov dx,offset message1 ; адрес начала строки - в DX
int 21h ; вызов системной функции DOS
mov ah,0ah ; номер функции ввода с клавиатуры - в АН
lea dx,buf ; адрес начала буфера ввода - в DX
int 21h ; вызов системной функции DOS
call ASCII ; вызов процедуры
mov a,ax ; сохранение результата
mov b,ax ; сохранение результата
mov ah,9 ; номер функции вывода на экран - в АН
mov dx,offset message2 ; адрес начала строки - в DX
int 21h ; вызов системной функции DOS
mov ah,0ah ; номер функции ввода с клавиатуры - в АН
lea dx,buf ; адрес начала буфера ввода - в DX
int 21h ; вызов системной функции DOS
call ASCII ; вызов процедуры
mov b,ax ; сохранение результата
mov c,ax ; сохранение результата
mov ah,9 ; номер функции вывода на экран - в АН
mov dx,offset message3 ; адрес начала строки - в DX
int 21h ; вызов системной функции DOS
mov ah,0ah ; номер функции ввода с клавиатуры - в АН
lea dx,buf ; адрес начала буфера ввода - в DX
int 21h ; вызов системной функции DOS
call ASCII ; вызов процедуры
mov c,ax ; сохранение результата
mov d,ax ; сохранение результата
mov ah,9 ; номер функции вывода на экран - в АН
mov dx,offset message4 ; адрес начала строки - в DX
int 21h ; вызов системной функции DOS
mov ah,0ah ; номер функции ввода с клавиатуры - в АН
lea dx,buf ; адрес начала буфера ввода - в DX
int 21h ; вызов системной функции DOS
call ASCII ; вызов процедуры
mov d,ax ; сохранение результата
mov e,ax ; сохранение результата
mov ah,9 ; номер функции вывода на экран - в АН
mov dx,offset message5 ; адрес начала строки - в DX
int 21h ; вызов системной функции DOS
mov ah,0ah ; номер функции ввода с клавиатуры - в АН
lea dx,buf ; адрес начала буфера ввода - в DX
int 21h ; вызов системной функции DOS
call ASCII ; вызов процедуры
mov e,ax ; сохранение результата
mov x,ax ; сохранение результата
mov ah,9 ; номер функции вывода на экран - в АН
mov dx,offset message6 ; адрес начала строки - в DX
int 21h ; вызов системной функции DOS
mov ah,0ah ; номер функции ввода с клавиатуры - в АН
lea dx,buf ; адрес начала буфера ввода - в DX
int 21h ; вызов системной функции DOS
call ASCII ; вызов процедуры
mov x,ax ; сохранение результата
;-------------
;вычисление значеня выражения
mov ax,a
mul x ; A*X
mov f,ax
mov ax,f
add ax,b
mov g,ax ;вычислили g
mov ax,x
mul x
mov h,ax
mov ax,c
mul h
mov i,ax
mov ax,d
mul x
mov j,ax
mov ax,i
add ax,j
mov k,ax ;вычислили k
mov ax,k
add ax,e
mov l,ax ;вычислили l
;-----------------------------
;вывести результат на экран
mov dx,offset message7
mov ah,9
int 21h
mov dx,ax
int 21h
mov ax,4ch
int 21h
;-------------
ret ; завершение программы
ASCII: ; метка процедуры
xor di,di ; DI = 0 - номер байта в буфере
xor ax,ax ; АХ = 0 - текущее значение результата
mov cl,blength
xor ch,ch
xor bx,bx
mov si,cx ; SI - длина буфера
mov cl,10 ; CL = 10, множитель для MUL
asc2hex:
mov bl,byte ptr bcontent[di] ; считываем очередной символ
sub bl,'0' ; цифра = код цифры - код символа "0",
jb asc_error ; если код символа был меньше, чем код "0",
cmp bl,9 ; или больше, чем "9",
ja asc_error ; выйти из программы с сообщением об ошибке,
mul cx ; иначе: умножить текущий результат на 10,
add ax,bx ; добавить к нему новую цифру,
inc di ; увеличить счетчик
cmp di,si ; если счетчик+1 меньше числа символов -
jb asc2hex ; продолжить (счетчик считается от 0)
ret ; завершение процедуры
asc_error:
mov dx,offset err_msg
mov ah,9
int 21h ; вывести сообщение об ошибке
mov ax,4c00h ; 4c - функция завершения программы (00=return 0)
;mov ah,4ch – можно записать одной командой, а можно двумя
;mov al,00h
int 21h ; и завершить программу
.data
message1 db 0Dh,0Ah, "Enter A : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода
message2 db 0Dh,0Ah, "Enter B : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода
message3 db 0Ah,0Dh, "Enter C : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода
message4 db 0Dh,0Ah, "Enter D : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода
message5 db 0Dh,0Ah, "Enter E : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода
message6 db 0Ah,0Dh, "Enter X : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода
err_msg db 0Dh,0Ah, "Error! ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода
message7 db 0Dh,0Ah, "Result: ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода
;-------------
;-------------
; Буфер ввода
buf db 10 ; максимальное кол-во символов
blength db ? ; для сохранения длины введённой строки
bcontent db 10 dup (32) ; для хранения введённой строки
a dw 0
b dw 0
c dw 0
d dw 0
e dw 0
x dw 0
f dw 0 ;для умножения
g dw 0
h dw 0
i dw 0
j dw 0
k dw 0
l dw 0
m dw 0 ;для умножения
end start ; конец программыРешение задачи: «Найти значение выражения. Не получается вывести результат на экран»
textual
Листинг программы
.model tiny ; модель (64 Кб) памяти, используемая для СОМ .code ; начало сегмента кода org 100h ; начальное значение счетчика инструкций (IP) - 100h start: ; метка начала программы, расположена по адресу 100h mov dx, offset message1 ; адрес начала строки - в DX call InputInt mov a, ax ; сохранение результата mov dx, offset message2 ; адрес начала строки - в DX call InputInt mov b, ax ; сохранение результата mov dx, offset message3 ; адрес начала строки - в DX call InputInt mov c, ax ; сохранение результата mov dx, offset message4 ; адрес начала строки - в DX call InputInt mov d, ax ; сохранение результата mov dx, offset message5 ; адрес начала строки - в DX call InputInt mov e, ax ; сохранение результата mov dx, offset message6 ; адрес начала строки - в DX call InputInt mov x, ax ; сохранение результата ;------------- ;вычисление значеня выражения mov ax,a mul x ; A*X mov f,ax mov ax,f add ax,b mov g,ax ;вычислили g mov ax,x mul x mov h,ax mov ax,c mul h mov i,ax mov ax,d mul x mov j,ax mov ax,i add ax,j mov k,ax ;вычислили k mov ax,k add ax,e mov l,ax ;вычислили l mov ax,g mov dx, 0 div l mov m,ax ;----------------------------- ;вывести результат на экран mov ah, 09h mov dx, offset message7 int 21h mov ax, m call OutInt ;завершение программы int 20h ; преобразования строки в число ; на входе: ; ds:[si] - строка с числом ; ds:[di] - адрес числа ; на выходе ; ds:[di] - число ; CY - флаг переноса (при ошибке - установлен, иначе - сброшен) Str2Num PROC push bx push cx push dx push ds push es push si push ds pop es mov cl, ds:[si] xor ch, ch 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 @@Error mov al, [si] ; Преобразуем следующий символ в число cmp al, '0' jb @@Error cmp al, '9' ja @@Error sub al, '0' xor ah, ah add ax, [di] jc @@Error ; Если сумма больше 65535 cmp ax, 8000h ja @@Error inc si loop @@Loop pop si ;проверка на знак push si inc si cmp byte ptr [si], '-' jne @@Check ;если должно быть положительным neg ax ;если должно быть отрицательным jmp @@StoreRes @@Check: ;дополнительная проверка, когда при вводе положительного числа получили отрицательное or ax, ax ; js @@Error @@StoreRes: ;сохранить результат mov [di], ax clc pop si pop es pop ds pop dx pop cx pop bx ret @@Error: xor ax, ax stc pop si pop es pop ds pop dx pop cx pop bx ret Str2Num ENDP ;ввод числа ;вход ; ds:dx - строка приглашение ;выход ; ax - введённое число InputInt proc push si @@Another: push dx mov ah, 09h ; номер функции вывода на экран - в АН ;mov dx,offset message1 ; адрес начала строки - в DX int 21h ; вызов системной функции DOS mov ah, 0ah ; номер функции ввода с клавиатуры - в АН lea dx, buf ; адрес начала буфера ввода - в DX int 21h ; вызов системной функции DOS pop dx lea si, buf+1 call Str2Num ; вызов процедуры jc @@Another pop si ret InputInt endp OutInt proc ;; если число знаковое, то необходимо расскоментировать следующие строки ;; Проверяем число на знак. test ax, ax jns oi1 ; ;; Если оно отрицательное, выведем минус и оставим его модуль. mov cx, ax mov ah, 02h mov dl, '-' int 21h mov ax, cx neg ax ;; Количество цифр будем держать в CX. oi1: xor cx, cx mov bx, 10 ; основание сс. 10 для десятеричной и т.п. oi2: xor dx,dx div bx ; Делим число на основание сс. В остатке получается последняя цифра. ; Сразу выводить её нельзя, поэтому сохраним её в стэке. push dx inc cx ; А с частным повторяем то же самое, отделяя от него очередную ; цифру справа, пока не останется ноль, что значит, что дальше ; слева только нули. test ax, ax jnz oi2 ; Теперь приступим к выводу. mov ah, 02h oi3: pop dx ; Извлекаем очередную цифру, переводим её в символ и выводим. ;; раскоментировать если основание сс > 10, т.е. для вывода требуются буквы ; cmp dl,9 ; jbe oi4 ; add dl,7 ;oi4: add dl, '0' int 21h ; Повторим ровно столько раз, сколько цифр насчитали. loop oi3 ret OutInt endp .data message1 db 0Dh,0Ah, "Enter A : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода message2 db 0Dh,0Ah, "Enter B : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода message3 db 0Ah,0Dh, "Enter C : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода message4 db 0Dh,0Ah, "Enter D : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода message5 db 0Dh,0Ah, "Enter E : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода message6 db 0Ah,0Dh, "Enter X : ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода err_msg db 0Dh,0Ah, "Error! ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода message7 db 0Dh,0Ah, "Result: ",0Dh,0Ah, '$' ; строка для вывода, символ $ - символ конца вывода ;------------- ;------------- ; Буфер ввода buf db 10 ; максимальное кол-во символов blength db ? ; для сохранения длины введённой строки bcontent db 10 dup (0) ; для хранения введённой строки a dw 0 b dw 0 c dw 0 d dw 0 e dw 0 x dw 0 f dw 0 ;для умножения g dw 0 h dw 0 i dw 0 j dw 0 k dw 0 l dw 0 m dw 0 ;для умножения end start ; конец программы