Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MUMPS СУБД. Практика применения и опыт программирования.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
5.2. ZTRAP 361
В определение обработчика ошибок входит 3 пункта: 1) что делать со стеком, 2) какой код нужно выполнить и 3) критерий окончания обработ­ки. В случае использования обработчика ZTRAP в Cach´e третий пункт выполняется автоматически, как только система выполнит переход на обработчик ошибок по неявной команде GOTO.
К отличительной особенности перехода по GOTO относится возмож­ность перейти на метку из различных точек выполняемого кода (строк), на которые мы можем попасть в различном контексте вызова - с ожида­нием возвращаемого значения или без. И, для того, чтобы обработчик корректно отнесся к возврату при выполнении неявной команды GOTO, нужно указать возврат в зависимости от значения системной переменной $QUIT. Покажем, как может сработать обработчик, не учитывающий контекст возврата:
proc() ; k w $$proc^ZTRAP() w
s $ztrap="err" w "in proc, $st=",$st,! w 1/0 w "exit proc, $st=",$st,! q 11
err
w "in err, $st=",$st,! q
Это тот же самый код, но предназначенный для вызова с возвратом значения:
USER>k w $$proc^ZTRAP() w in proc, $st=1 in err, $st=1
K W $$proc^ZTRAP() W
^ <COMMAND> USER>
Здесь команда QUIT в обработчике ошибок вошла в конфликт по сво­ей форме (безаргументной) с контекстом вызова с ожиданием возврата. Чтобы исправить ситуацию и сделать обработчик ошибки более универ­сальным, модифицируем его, чтобы учитывалось значение $QUIT:
proc() ; k w $$proc^ZTRAP() w
s $ztrap="err" w "in proc, $st=",$st,! w 1/0
362 ГЛАВА 5. ОБРАБОТКА ОШИБОК
w "exit proc, $st=",$st,! q 11
err
w "in err, $st=",$st,! q:$Q "was error" q
И этот вариант уже корректно срабатывает в обоих случаях вызова:
USER>k w $$proc^ZTRAP() w in proc, $st=1 in err, $st=1 was error USER>d proc^ZTRAP in proc, $st=1 in err, $st=1
В случае если в обработчике ошибки также происходит ошибка, то при его срабатывании также вызывается обработчик ошибок. Если про­граммист не изменил значение $ZTRAP, то при его выполнении про­грамма зацикливается. Приведем модифицированный пример для иллю­страции:
proc() ; k w $$proc^ZTRAP() w
s count=0 s $ztrap="err" w "in proc, $st=",$st,! w 1/0 w "exit proc, $st=",$st,! q 11
err
i count=1 w "already in err",! q:$Q "was error" q s count=1 w "in err, $st=",$st,! w 1/0 q:$Q "was error" q
При его выполнении получаем отчет о ходе обработки ошибки:
USER>k w $$proc^ZTRAP() w in proc, $st=1 in err, $st=1 already in err was error count=1 USER>
Другим способом избежать зацикливание в обработчике ошибок яв­ляется самостоятельная очистка текущего обработчика ошибок $ZTRAP в самом обработчике:
5.2. ZTRAP 363
proc() ; k w $$proc^ZTRAP() w
s $ztrap="err" w "in proc, $st=",$st,! w 1/0 w "exit proc, $st=",$st,! q 11
err
s $zt="" w "in err, $st=",$st,! w 1/0 q:$Q "was error" q
В этом случае процесс, попав в обработчик, в нем использует обра­ботчик ошибок, установленный на более высоком уровне, или, если он не был установлен, то переходит к обработке ошибки по умолчанию:
USER>k w $$proc^ZTRAP() w in proc, $st=1 in err, $st=1
w 1/0
^ <DIVIDE>err+3^ZTRAP USER 2e0>
При использовании системы Cach´e и обработчика в стиле ZTRAP программисты чаще всего выбирают типовой способ его использования с такими условиями:
1. Обработчик используется без указания символа "*", чтобы вне за­висимости от глубины стека где произошла ошибка, управление было передано на код, указанный программистом при установке обработчика.
2. Обработчик устанавливается во всех функциях, где это важно, и с самого верхнего уровня. Во вспомогательных функциях-утилитах из разряда преобразований данных обработчик обычно не указы­вается.
3. В самом коде обработчика ошибок значение обработчика $ZTRAP предварительно очищается во избежание зацикливания и чтобы код мог перейти на обработку ошибки на более верхнем уровне стека.
364 ГЛАВА 5. ОБРАБОТКА ОШИБОК
При этом нужно понимать, что выбор характера обработки ошибок в каждом проекте может отличаться из-за различных методик или необхо­димости предпринимать какие-то особенные для прикладной программы действия. Для этого изучаются требования к проекту, особенности ра­боты обработчика ошибок в определенной MUMPS системе или даже ее версии, и составляются правила его применения, чтобы группа програм­мистов - участников проекта им далее следовала.
Старшие версии Cach´e также дополнительно проверяют синтаксис значения $ZTRAP при присваивании и в случае недопустимого синтак­сиса генерируют ошибку <SYNTAX>:
USER>s $zt="w w"
S $ZT="w w" ^ <SYNTAX>
5.2.2 MSM
В системе MSM поведение обработчика ZTRAP почти в точности ана­логично его поведению в системе Cach´e, но с такими отличиями:
1. Не поддерживается символ "*" перед меткой обработчика ошибок и MSM всегда передает управление на тот уровень стека, где он был установлен последним.
2. Перед выполнением неявной команды GOTO для передачи управ­ления на код обработчика ошибок значение обработчика $ZTRAP автоматически сбрасывается в значение пустая строка.
И, также как и в Cach´e, в системе MSM критерием выхода процесса из состояния ошибки является передача управления неявной командой GOTO на метку обработчика.
Таким образом, для организации полностью совместимой между Cach´e и MSM обработки ошибок с помощью ZTRAP нужно, чтобы програми­сты не использовали символ "*" перед именем метки в значении $ZTRAP, и в коде обработчика сбрасывали значение $ZTRAP в значение пустая строка. И большинство программ, разрабатываемых как для MSM, так и для Cach´e, действительно придерживается таких правил.
5.2. ZTRAP 365
5.2.3 DTM
В системе DTM (Data Tree MUMPS) обработчик ZTRAP также аналоги­чен по поведению системе MSM, но у программиста дополнительно есть команда ZQUIT. Если код обработчика ошибок заканчивается командой QUIT, то управление передается на тот уровень стека, на котором про­изошла ошибка, а если командой ZQUIT, то управление передается на обработчик ошибок, установленный раньше по стеку.
5.2.4 M3
В MUMPS системе M3 (в настоящее время доступна реализация M3­Lite) обработчик ZTRAP используется в зависимости от синтаксиса со­держания системной переменной $ZTRAP.
Если значение $ZTRAP синтаксически соответствует имени метки, то при обработке ошибки процесс выполняет возврат по стеку на уро­вень где было выполнено присваивание $ZTRAP и выполняет неявную команду GOTO на указанную метку.
В случае если значение $ZTRAP синтаксически соответствует после­довательности команд, то они выполняются вместо строки, на которой произошла ошибка. В этом случае код команд должен выполнить пере­дачу управления на иную строку командой GOTO или возврат командой QUIT.
В случае если присваивается пустая строка, то обработчик на этом уровне стека отменяется и далее процесс будет использовать обработчик, указанный ранее по стеку.

5.2.5 GT.M

В системе GT.M обработчик ZTRAP устроен, видимо, наиболее слож­ным образом из современных MUMPS систем. Ключевая часть его функ­ционала, видимо, и послужила прототипом для определения стандартно­го обработчика ошибок ETRAP.
К формальному определению $ZTRAP в системе GT.M можно отне­сти то, что эта системная переменная должна содержать последователь­ность команд, которые будут выполнены на манер команды XECUTE. К дополнительным синтаксическим возможностям относится то, что она может быть аргументом команды NEW и система GT.M различает, на каком уровне стека был определен обработчик ошибок - если была при­менена команда NEW явно, то на этом же уровне стека, иначе присваи­вание системной переменной $ZTRAP изменяет значение на том уровне
366 ГЛАВА 5. ОБРАБОТКА ОШИБОК
стека где она была заведена ранее.
По умолчанию команда NEW, примененная к переменной $ZTRAP, автоматически сбрасывает ее в значение пустая строка, поэтому обычно следующей же командой идет присваивание $ZTRAP обработчика оши­бок. В системе GT.M, в отличие от других, пустое значение не является признаком обработчика по умолчанию. Если процесс попал в состоя­ние ошибки при пустом $ZTRAP, то он завершает работу. В началь­ном состоянии процесса после его старта значение $ZTRAP равно "B", что означает необходимость выполнить при ошибке команду BREAK, то есть перейти в непосредственный режим управления процессом (Direct Mode), и управление передается оператору для непосредственного вво­да команд. При этом в системе GT.M имеется управление поведением присваивания $ZTRAP через переменную окружения - если значение переменной окружения gtm_ztrap_new вычисляется как TRUE, YES или ненулевое число, то любое присваивание $ZTRAP приводит к неявному выполнению команды NEW для $ZTRAP перед присваиванием. При­менение NEW к переменной $ZTRAP позволяет сохранить предыдущие определения обработчиков ошибок и автоматически восстановить преды­дущее значение при возврате по стеку. В отличие от определения ZTRAP в Cach´e, в GT.M обработчик ошибок всегда выполняется на том же уровне стека где произошла ошибка, без автоматического возврата по стеку к месту установки $ZTRAP.
Формально говоря, при возникновении ошибки в исполняемой стро­ке, процесс GT.M переходит в состояние выполнения строки $ZTRAP как если бы она была вместо исполняемой строки, или XECUTE без ор­ганизации нового уровня стека. Критерий окончания состояния ошибки
- начало выполнения этой строки. При этом система GT.M различает, в каком качестве и как использовать содержание переменной $ZTRAP.
В зависимости от значения переменной окружения gtm_ztrap_form, процесс GT.M использует значение $ZTRAP следующими способами (по умолчанию поведение GT.M соответствует значению code):
code Значение $ZTRAP используется как последо-
вательность команд, выполняемых при ошиб­ке. Если управление не было передано коман­дами GOTO, ZGOTO или QUIT какой-либо другой строке кода, то после выполнения кода $ZTRAP управление снова передается на нача­ло строки, вызвавшей ошибку.
5.2. ZTRAP 367
entryref Значение $ZTRAP используется как имя мет-
ки для передачи управления неявной командой GOTO.
adaptive Если значение $ZTRAP синтаксически являет-
ся последовательностью команд, то использует­ся как было описано для "code", иначе исполь­зуется как было описано для "entryref". В этом случае процесс GT.M применяет распознавание синтаксиса и действует адаптивно.
popentryref Процесс GT.M возвращается по стеку на уро-
вень, где было произведено последнее присваи­вание $ZTRAP и использует его значение как имя метки для выполнения неявной команды GOTO для передачи управления.
popadaptive Процесс GT.M возвращается по стеку на уро-
вень, где было произведено последнее присва­ивание $ZTRAP и использует его значение в зависимости от синтаксиса - если это после­довательность команд то они выполняются, ес­ли имя метки то на нее передается управления неявной командой GOTO.
Кроме того, процесс GT.M использует еще одну переменную окруже­ния процесса - переменную gtm_zyerror. Если ее значение синтаксически соответствует имени метки, то при значениях переменной gtm_ztrap_form, равным popentryref или popadaptive, процесс после возврата по стеку вы­полняет неявную команду DO для метки, указанной в переменной окру­жения gtm_zyerror, и лишь после возврата из нее передает управление либо последовательности команд, либо метке, указанным в $ZTRAP.
В качестве иллюстрации поведения $ZTRAP приведем пример из документации GT.M при присваивании переменной $ZTRAP последова­тельности команд:
GTM>ZPRINT ^EP6 EP6 WRITE !,"THIS IS "_$TEXT(+0)
BAD SET CB=CB+1 WRITE A SET CE=CE+1
NEW NEW $ZTRAP SET $ZTRAP="DO ET" SET (CB,CE)=0
WRITE !,"AFTER SUCCESSFUL EXECUTION OF BAD:",! SET A="A IS NOT DEFINED" ZWRITE QUIT
368 ГЛАВА 5. ОБРАБОТКА ОШИБОК
ET W !,"CONTINUING WITH ERROR TRAP AFTER AN ERROR",!
GTM>do ^EP6
THIS IS EP6 CONTINUING WITH ERROR TRAP AFTER AN ERROR CB=1 CE=0 A IS NOW DEFINED AFTER SUCCESSFUL EXECUTION OF BAD: A="A IS NOT DEFINED" CB=2 CE=1
GTM>
ZWRITE SET A="A IS NOW DEFINED"
Здесь при выполнении строки BAD генерируется ошибка неопреде­ленного значения A, вызывается обработчик ошибок в виде последова­тельности команд
DO ET
в котором корректируется ошибка с определенностью переменной A.
Затем снова управление снова передается на строку BAD и в при­мере показывается, что оператор увеличения CB выполнился дважды, а увеличения CE - единожды.
Тот же алгоритм обработки ошибки с использованием стандартно­го обработчика ETRAP, с возвратом управления на строку, вызвавшую ошибку, выполняется таким способом:
GTM>ZPRINT ^EP6A EP6A WRITE !,"THIS IS "_$TEXT(+0)
BAD SET CB=CB+1 WRITE A SET CE=CE+1
ET W !,"CONTINUING WITH ERROR TRAP AFTER AN ERROR",!
NEW NEW $ETRAP SET $ETRAP="GOTO ET" SET (CB,CE)=0
WRITE !,"AFTER SUCCESSFUL EXECUTION OF BAD:",! ZWRITE QUIT
ZWRITE SET A="A IS NOW DEFINED" SET RETRY=$STACK($STACK,"PLACE") SET $ECODE=""
5.2. ZTRAP 369
GOTO @RETRY
GTM>DO ^EP6A
THIS IS EP6A CONTINUING WITH ERROR TRAP AFTER AN ERROR CB=1 CE=0 A IS NOW DEFINED AFTER SUCCESSFUL EXECUTION OF BAD: A="A IS NOW DEFINED" CB=2 CE=1 RETRY="BAD^EP6A"
GTM>
Здесь для выполнения возврата на строку имя строки с ошибкой вычисляется обращением к системной переменной $STACK и системной функции $STACK. И в обработчике ошибок $ETRAP, и в конце кода обработчика используются команды GOTO, сохраняющие уровни стека.

5.2.6 MiniM

В системе MiniM обработчик ZTRAP также выполнен с отличитель­ными особенностями поведения, не совпадающими в точности с други­ми MUMPS системами. Вообще говоря, в системе MiniM отсутствует отдельный механизм обработки ошибок ZTRAP как таковой, и при­сутствует только обработчик ETRAP. Системная переменная $ZTRAP в MiniM используется исключительно для определенного уровня син­таксической совместимости с имеющимся кодом и при присваивании $ZTRAP в действительности выполняется присваивание системной пе­ременной $ETRAP в зависимости от содержания $ZTRAP.
В системе MiniM значение $ZTRAP сохраняется единственным для всех уровней стека, вне зависимости от уровня на котором производи­лось присваивание.
При присваивании значения системной переменной $ZTRAP произво­дится анализ его содержания и выполняются операции с присваиванием и команда new с системными переменными $ESTACK и $ETRAP в за­висимости от содержания $ZTRAP. В значении системной переменной $ZTRAP допускается либо имя метки для перехода по команде goto, либо метка и дополнительный символ "*" перед ней.
370 ГЛАВА 5. ОБРАБОТКА ОШИБОК
Если значение $ZTRAP при присваивании содержит только метку,
то при этом выполняется код эквивалентный коду:
new $estack new $etrap set $etrap="g:’$es "_$ztrap
Это соответствует раскручиванию стека выполнения до того уровня, на котором был установлен обработчик, и переходу на обработчик по команде goto.
Если значение $ZTRAP при присваивании содержит символ "*" перед меткой, то при этом выполняется код, эквивалентный коду:
set $etrap="g "_$e($ztrap,2,$l($ztrap))
Это соответствует переходу на обработчик ошибок на уровень стека, на котором возникла ошибка:
USER>s $zt="err^errhandler"
USER>w $et g:’$es err^errhandler USER>s $zt="*err^errhandler"
USER>w $et g err^errhandler
В случае, если системной переменной $ZTRAP присваивается значе­ние не соответствующее ни одной допустимой форме, то процесс MiniM генерирует ошибку <SYNTAX>.
Поскольку в MiniM обработчик ZTRAP есть только переходник на обработчик ETRAP, для выполнения кода совместимого по поведению с другими MUMPS системами необходимо в коде обработчика очистить значение системной переменной $ECODE. Эту очистку надо разместить после того, как значение $ECODE было использовано, например, так:
n ec s ec=$ec s $ec=""
В этом случае обработка ошибки будет закончена выполнением кода обработчика. Иначе, без очистки значения $ECODE при возврате из обработчика, будет продолжена раскрутка стека до передачи управления обработчику, установленному ранее.