Д. В. Якошвили, г Москва

ПРИРУЧЕНИЕ «ХИЩНИКОВ»

Неприятно, когда в самом неподходящем месте красиво оформленного экрана появляется надпись «СТОП В СТРОКЕ 120» или «ОШИБКА 5 В СТРОКЕ 10» Бейсик беззащитен перед этими двумя «хищниками» - прерыванием из-за нажатия клавиши СТОП и при возникновении ошибки. О программной обработке прерывания при нажатии клавиши СТОП уже было рассказано в ИНФО, 1992, №2; 1993, №4. Займёмся теперь делом совсем новым - укрощением ошибок. В развитых версиях Бейсика для этого есть конструкция ON ERROR GOTO список номеров строк. Нам же предстоит смоделировать её.

Сообщения об ошибках выдаются при исполнении команды ассемблера TRAP (прерывание по вектору 34(8)) с номерами 0-77(8). (О принципе работы TRAP см. статью Ю. Зальцмана «Архитектура и ассемблер БК», ИНФО, 1991, №2.) Надо написать кодовый фрагмент, который «отлавливал» бы прерывания по вектору 34(8), «отпускал» на стандартное исполнение команды TRAP с номерами, большими 77(8) (их Бейсик использует для служебных целей), а от остальных оставлял только номер в форме, удобной для обработки в Бейсике, чтобы мы могли узнать, какая это ошибка.

Вот текст этого фрагмента

;--------------------------------------------------------------
        MOV R0,-(SP)    ;       Сохранить в стеке R0
        MOV 2(SP),R0    ;       Поместить в R0 адрес команды,
                        ;       следующей после TRAP
        MOVB -2(R0),R0  ;       Получить в R0 номер TRAP
        CMP R0,#77      ;       Номер превышает 77 (восьм.)?
        BLOS 1  ;
        MOV (SP)+,R0    ;       Если да, то восстановить R0
        JMP @#146404    ;       и передать управление стандарт-
                        ;       ному TRAP-диспетчеру
1:      MOV R0,ERR      ;       Иначе занести номер TRAP в
        MOV (SP)+,R0    ;       ячейку ERR, восстановить R0,
        MOV #A,(SP)     ;       подменить адрес возврата из
                        ;       прерывания на адрес фрагмента
                        ;       перехода в начало шитого кода
        RTI             ;       и выйти из прерывания
;--------------------------------------------------------------
A:      MOV (PC)+,R4    ;       Занести для Бейсика в R4 адрес
                        ;       начала шитого кода,
        WORD 0          ;       который Бейсик-программа
                        ;       поместит сюда вместо нуля,
        JMP @(R4)+      ;       и перейти по этому адресу
;--------------------------------------------------------------
ERR:    .WORD 0 ;       Номер ошибки

Длина фрагмента - 52(8) байта. При трансляции с адреса 1000(8) А=1042(8), ERR=1050(8).

Итак, у нас есть программа в кодах, которая будет при возникновении ошибки помещать её номер в ячейку 1050(8) и передавать управление на начало Бейсик-программы. Теперь можно написать саму Бейсик-программу, обрабатывающую прерывания и от клавиши СТОП, и от ошибок:

10 IF PEEK(4%)=-24420% THEN 50
15 '
20 IF PEEK (&O1050)=0% THEN 280 ELSE 350
25 ' THEN <stop> ELSE <error>
30 DATA 4134,7552,2,-25600,-2,8215,63,-31997,5504,95,-13052
40 DATA 4151,14,5504,5582,546,2,5572,0,92,0
45 '
50 FOR J%=&O1000 TO &O1050 STEP 2%
60 READ C%
70 POKE J%,C%
80 NEXT J%
85 '
90 POKE &O1044,PEEK(1026%)+PEEK(1026%)MOD2%
100 POKE 4%,&O1042
110 POKE &O34,&O1000
200 INPUT "ВВЕДИТЕ ЧИСЛО";A
210 C=SQR(1/A)
220 ? "SQR(1/число)=";C
230 ? "Для выхода нажмите СТОП"
240 GOTO 200
250 '
260 '
270 '
280 '  Обработка СТОП:
290 POKE 4%,-24420% ' Восстановление векторов
300 POKE 28%,-13052% ' "СТОП" и "TRAP" (&O34=28%)
310 ? "До свидания..."
320 END
330 '
340 '
350 ' обработка ОШИБОК:
360 C%=PEEK (&O1050) ' Номер ошибки - C%
370 POKE &O1050,0% ' Обнулить ячейку !!!
375 ? "НОМЕР ОШИБКИ:";C%
380 IF C%=5% THEN ? "Корень из отрицательного числа"
390 IF C%=11% THEN ? "Деление на ноль"
400 ? "Повторите ввод числа"
410 GOTO 200

В строке 20 записаны номера первых строк Бейсик-модулей обработки прерывания от СТОП (строка 280) и от ошибки (строка 350). На эти строки управление передаётся только при возникновении одного из указанных прерываний.

Как видно из строки 20, тип прерывания БК определяет по ячейке 1050(8) (ERR):

РЕЕК(&O1050)=0 - прерывание от СТОП,

РЕЕК(&О1050)≠0 - прерывание из-за ошибки.

Поэтому в Бейсик-модуле обработка ошибок не забывайте обнулять ячейку 1050(8)! (В приведённом примере это делается в строке 370.) Иначе машина любое прерывание будет считать произошедшим из-за ошибки.

Условие в строке 10 выполняется лишь при запуске, поэтому в первый раз управление после неё переходит к блоку 50-80, который вводит в память приведённый выше кодовый фрагмент, заключённый в блоке данных 30-40. (Он размещается в области стека Бейсика начиная с адреса 1000(8). - Прим, ред.)

Строка 90 заносит в ячейку, следующую за меткой «А:», адрес начала шитого кода, как это оговорено в комментарии к ассемблерному листингу.

Строки 100 и 110 переопределяют векторы прерываний 4 и 34(8)

Оставшаяся часть программы (строки 200-410) приведена в качестве примера. Запустите Бейсик-программу и поочерёдно вводите на запрос числа: -10, 0, К, 2Е40 (два последних случая - ошибки 13 и 6, соответственно) Создайте ситуацию ошибки 25 (вводимая строка длиннее, чем 256 символов) - нажмите 2. а потом клавишу ПОВТ и удерживайте её нажатой.

 

Performed by © gid, 2012-2022.