Консультация № 19813
16.04.2005, 07:53
0.00 руб.
0 3 3
Здравствуйте!
Пишу резидентный калькулятор. Исходник в приложении.
Проблема в следующем - резидент не работает! Не могу понять
почему после перехода на процедуру Calculator прога виснет. Как
мне кажеться проблема с вводом строки. Можно ли в резиденте
читать с клавы с помощью 0Ah функции int 21h ? Или может проблема
все таки не в вводе? Помогите плз!
И еще, может у кого есть готовая процедура вывода числа с плавающей
точкой на екран? Как, после того как вычисления сделаны, снова вернуть
командную строку Доса, и при этом оставить прогу резидентной?
Заранее большое спасиба за все ответы!
;;;;;;;;;;;;;;;;;;;;;;файл resident.asm
.MODEL Tiny
.286
.CODE
ORG 100h
Start:

jmp SetIntVec ; встановлення обробника переривань
INCLUDE calc.asm
stdout equ 1
alt_q equ 1000h
endmes db "Program was erased..."
endmesl equ $-endmes
Handler09 PROC ; обробник переривання
push bx ds ; зберігаєм BX и DS
push cs
pop ds ; DS = CS
mov ax,cs
mov ds,ax

mov ax,40h
mov es,ax

; обробка символа з кільцевого буфера без прямого видобування
mov bx,es:1Ah
mov ax,es:[bx]
cmp ax,alt_q
je altq
cmp ah,1Fh ; ALT-S show
jne next
call Calculator ;
jmp home
next:
cmp ah,23h ; ALT-H hide
jne home
home:
pop ds bx ; відновлюєм BX і DS
; Передаєм управління старому обробнику
db 0EAh ; jmp large
RealAddr09 dd ? ; Адрес переходу
altq:
; відновити вектор без застосування функцій DOS
mov ax, 0
mov es, ax
mov ax, word ptr RealAddr09
mov word ptr es:24h, ax
mov ax, word ptr RealAddr09 + 2
mov word ptr es:26h, ax
; завершити роботу обробника / вивести повідомлення
mov ax, cs
mov ds, ax
mov ah, 9
mov dx, offset endmes
int 21h
; вивести повідомлення
mov ah, 40h
mov bx, stdout
mov cx, endmesl
mov dx, offset endmes
int 21h

jmp home
Handler09 ENDP ; кінець обробника int 09h
TSREnd = $ ; кінець резидентної частини

mes db ‘Program is now resident...‘,10,13
meslen equ $-mes
SetIntVec:
mov ax, 3509h
int 21h ; получаємо вектор переривання 09h
mov word ptr RealAddr09[0], bx ; і зберігаємо його ...
mov word ptr RealAddr09[2], es ; в RealAddr09
mov ah,25h ; AL ми не міняли
lea dx,Handler09
int 21h ; встановлюємо новий обробник переривань int 09h
; вивести повідомлення
mov ah,40h
mov bx,stdout
mov cx,meslen
mov dx, offset mes
int 21h

mov ah,49h
mov es,ds:[2Ch] ; сегмент, змінні середовища
int 21h ; звільняжмо його
lea dx,TSREnd
int 27h ; виходимо зберігаючи резидентну частину
END Start

Приложение:
Calculator PROC mov ax,cs mov ds,ax ; читати рядок символів у буфер mov ah, 0Ah mov dx, offset buffer int 21h ; розділення буфера на "число", "знак", "число" ; Перевірка на cos(x) mov al, byte ptr bcont cmp al, byte ptr "c" jne not_cos mov al, byte ptr bcont + 1 cmp al, byte ptr "o" jne not_cos mov al, byte ptr bcont + 2 cmp al, byte ptr "s" jne not_cos mov al, byte ptr bcont + 3 cmp al, byte ptr "(" jne not_cos ; Знайшли cos(x) зчитати символи з ( до ) mov cl, buflen sub cl, 5 ; мінус довжина соs і () mov di, 4 ; починаємо читати з 4 символа xor al, al xor si, si mov byte ptr num1_len, al cos_op: ; перевірка співпадіння з ")" mov al, byte ptr ")" cmp byte ptr bcont [di], al je cos_end ; копіювання в першу стрічку mov al, byte ptr bcont[di] mov num1[si] , al inc di inc byte ptr num1_len inc si dec cl jnz cos_op cos_end: mov al, "c" mov op, al ; операція - косинус jmp done not_cos: ; перевірка на синус mov al, byte ptr bcont cmp al, byte ptr "s" jne not_sin mov al, byte ptr bcont + 1 cmp al, byte ptr "i" jne not_sin mov al, byte ptr bcont + 2 cmp al, byte ptr "n" jne not_sin mov al, byte ptr bcont + 3 cmp al, byte ptr "(" jne not_sin ; Знайшли sin(x) зчитати символи з ( до ) mov cl, buflen sub cl, 5 ; мінус довжина sin і () mov di, 4 ; починаємо з 4 символа xor al, al xor si, si mov byte ptr num1_len, al sin_op: ; перевірка співпадіння з ")" mov al, byte ptr ")" cmp byte ptr bcont [di], al je sin_end ; копіювання в першу стрічку mov al, byte ptr bcont[di] mov num1[si] , al inc di inc byte ptr num1_len inc si dec cl jnz sin_op sin_end: mov al, "s" mov op, al ; операція - синус jmp done not_sin: ; обробка х (операція) у mov cl, buflen xor di, di xor al, al mov byte ptr num1_len, al lp1: ; перевірка співпадіння з знаками опрацій mov al, byte ptr plus cmp byte ptr bcont [di], al je lpend mov al, byte ptr minus cmp byte ptr bcont [di], al je lpend mov al, byte ptr mult cmp byte ptr bcont [di], al je lpend mov al, byte ptr divi cmp byte ptr bcont [di], al je lpend ; копіювання в першу стрічку mov al, byte ptr bcont[di] mov num1[di] , al inc di inc byte ptr num1_len dec cl jnz lp1 lpend: ; знайшли знак операції mov al, byte ptr bcont[di] mov op, al inc di xor si,si ; продовжуємо копіювати в другу стрічку lp2: dec cl jz done mov al, byte ptr bcont[di] mov num2[si], al inc si inc di inc byte ptr num2_len jmp lp2 done: ; відокремлення цілої і дробової частини ; перше число mov cl, num1_len xor di, di lp3: ; порівняння текучого символа з комою mov al, byte ptr point cmp byte ptr num1 [di], al je lpend1 ; якщо не кома - копіювати в цілу частину першого числа mov al, byte ptr num1[di] mov byte ptr num1_whole [di] , al inc di inc byte ptr num1_w_len ; збільшити довжину числа dec cl jnz lp3 lpend1: inc di xor si, si dec cl ; копіювання решти стрічки в дробову частину першого іисла lp4: mov al, byte ptr num1 [di] mov byte ptr num1_fract [si], al inc di inc si inc byte ptr num1_f_len dec cl jnz lp4 cont1: ; друге число cmp op, byte ptr "c" je cont2 cmp op, byte ptr "s" je cont2 mov cl, num2_len xor di, di lp5: ; пошук коми mov al, byte ptr point cmp byte ptr num2 [di], al je lpend2 mov al, byte ptr num2[di] mov byte ptr num2_whole [di] , al inc di inc byte ptr num2_w_len dec cl jnz lp5 lpend2: inc di xor si,si dec cl ; копіювання дробової частини lp6: mov al, byte ptr num2 [di] mov byte ptr num2_fract [si], al inc di inc si inc byte ptr num2_f_len dec cl jnz lp6 cont2: ; Перевід рядків в числа BCD xor si, si xor cx, cx xor di, di mov cl, byte ptr num1_w_len mov si, offset num1_whole add si, cx dec si mov di, offset n1_w call Conv2BCD xor si, si xor cx, cx xor di, di mov cl, num1_f_len mov si, offset num1_fract add si, cx dec si mov di, offset n1_f call Conv2BCD xor si, si xor cx, cx xor di, di mov cl, num2_w_len mov si, offset num2_whole add si, cx dec si mov di, offset n2_w call Conv2BCD xor si, si xor cx, cx xor di, di mov cl, num2_f_len mov si, offset num2_fract add si, cx dec si mov di, offset n2_f call Conv2BCD ; Виконання обчислень з використанням FPU docalc: finit ; ініціалізація fbld n1_f ; загрузити в стек дробову частину першого числа mov cl, num1_f_len ; довжина дробової частини fld1 ; завант. 1 c1: fild word ptr _10 ; завант. 10 fmul ; перемножити dec cl cmp cl, 0 ; повторити множення 10*10*... стільки раз jnz c1 ; скільки є чивр в дробовій частині fdiv ; поділити - одержати дробову чатину fbld n1_w ; завант. цілу част. fadd ; додати - вершина стеку - перше число cmp byte ptr op, byte ptr "c" je calc cmp byte ptr op, byte ptr "s" je calc fbld n2_f mov cl, num2_f_len fld1 c2: fild word ptr _10 fmul dec cl cmp cl, 0 jnz c2 fdiv fbld n2_w fadd calc: mov al, byte ptr op cmp al, byte ptr plus jne op_minus fadd jmp op_end op_minus: cmp al, byte ptr minus jne op_mul fsub jmp op_end op_mul: cmp al, byte ptr mult jne op_div fmul jmp op_end op_div: cmp al, byte ptr divi jne op_sin fdiv jmp op_end op_sin: cmp al, byte ptr "s" jne op_cos .386 .387 fsin .186 jmp op_end op_cos: .386 .387 fcos .186 op_end: fstp res32 ; считати і виштовхнути з стеку ; fst res32 - считати і не виштовхувати retCalculator ENDPConv2BCD PROC m1: std xor ax, ax lodsb and al, 0fh shl ax, 8 lodsb cmp al, 0 jne not0 xor al, al not0: and al, 0fh shl al, 4 add al, ah cld stosb sub cx,2 cmp cx, 0 jg m1 retConv2BCD ENDP res32 dd 0 plus db ‘+‘ minus db ‘-‘ mult db ‘*‘ divi db ‘/‘ point db ‘.‘ num1 db 21 dup (0) num2 db 21 dup (0) num1_len db 0 num2_len db 0 op db ? z db 0 num1_whole dt 0 num2_whole dt 0 num1_fract dt 0 num2_fract dt 0 n1_w dt 0 n2_w dt 0 n1_f dt 0 n2_f dt 0 t db 0 num1_w_len db 0 num2_w_len db 0 num1_f_len db 0 num2_f_len db 0 tmp dt 0 _10 dw 10 buffer db 255 buflen db ? bcont db 255 dup (0)

Обсуждение

давно
Советник
419
1011
16.04.2005, 08:56
общий
это ответ
Здравствуйте, x3m!
в обработчике прерывания не сохраняются регистры, а точнее AX и другие.
Неизвестный
18.04.2005, 11:32
общий
это ответ
Здравствуйте, x3m!
1. Никаких прерываний int21h быть не должно, пользуйся int16h
2. push bx ds - очень мало - Сохранять нужно все используемые регистры (включая сопроцессор)
3. См. ниже
4. При отсутствии ошибок в calc.asm (не смотрел) и соблюдении п.п. 1 и 2 все будет работать...

Приложение:
.386float2char proc;cx-число цифр после запятой,number-число,es:di - адрес строки pushad xor edx,edx xor eax,eax inc al fninit;сброс сопроцессора fld number;загрузить число jcxz @@int xor ebx,edx mov bl,10 push cx@@mul: mul ebx loop @@mul pop cx mov dword ptr[cs:number],eax fimul dword ptr[cs:number]@@int: fbstp [cs:BCD];Извлечь число в коде BCD mov AX,cs:BCD[8];Проверить результат на переполнение cmp AX,0FFFFh;Число слишком большое - слишком много цифр je @@Overflow mov AL,cs:BCD[9];Выделить знак числа and AL,AL jz @@pos mov AL,‘-‘ stosb@@pos: ;Расшифровка полученного BCD числа, помня, куда надо ставить запятую (сх символов от конца)... - вставь свою... popad ret number dq 123.456789 BCD db 10 dup (?) endp.186
Неизвестный
19.04.2005, 00:44
общий
это ответ
Здравствуйте, x3m!
Ты вызываешь процедуру CALC из прерывания INT9 - т.е. у тебя запрещены все прерывания и клава работать не будет. Пока корректно не выйдешь из Int9.
Т.е. тебе надо переместить вызов CALC скажем в int2f(по флагу), а в Int9 поставить флаг.
Форма ответа