Special Forms
AutoLISP Basics
Using the *error* Function
Error Handling in AutoLISP
The AutoLISP language provides several
functions for error handling. You can use these functions to do
the following:
- Provide information
to users when an error occurs during the execution of a program. - Restore the AutoCAD environment
to a known state. - Intercept errors and
continue program execution.
The complete list of error-handling
functions is in AutoLISP Function Synopsis under the heading Error-Handling Functions Each error-handling function
is described in the AutoLISP
Reference.
If your program contains
more than one error in the same expression, you cannot depend on
the order in which AutoLISP detects the errors. For example, the inters function
requires several arguments, each of which must be either a 2D or
3D point list. A call to inters like
the following:
is an error on two counts:
too few arguments and invalid argument type. You will receive either
of the following error messages:
; *** ERROR: too few arguments
; *** ERROR: bad argument type: 2D/3D point
Your program should be designed
to handle either error.
Note also that in AutoCAD,
AutoLISP evaluates all arguments before checking the argument types.
In previous releases of AutoCAD, AutoLISP evaluated and checked
the type of each argument sequentially. To see the difference, look
at the following code examples:
(defun foo ()
(print "Evaluating foo")
'(1 2))
(defun bar ()
(print "Evaluating bar")
'b)
(defun baz ()
(print "Evaluating baz")
'c)
Observe how an expression
using the inters function
is evaluated in AutoCAD:
Command: (inters (foo) (bar)
(baz))
«Evaluating foo»
«Evaluating bar»
«Evaluating baz»
; *** ERROR: too few
arguments
Each argument was evaluated
successfully before AutoLISP passed the results to inters and
discovered that too few arguments were specified.
In AutoCAD Release 14 or earlier,
the same expression evaluated as follows:
Command: (inters (foo) (bar)
(baz))
«Evaluating foo»
«Evaluating bar» error:
bad argument type
AutoLISP evaluated (foo),
then passed the result to inters.
Since the result was a valid 2D point list, AutoLISP proceeds to
evaluate (bar),
where it determines that the evaluated result is a string, an invalid
argument type for inters.
- Using the *error* Function
-
Catching Errors and Continuing
Program Execution
Errors caused by AutoLISP functions can result in a program ending unexpectedly, make sure to handle all known situations that could cause an error.
- Wrap each function that could throw an error with
vl-catch-all-apply. - Evaluate the value returned by
vl-catch-all-apply with
vl-catch-all-error-p to see if an error object or a value was returned. - Use
vl-catch-all-error-message to get the message associated with the returned error object. - Load, run, and test the code.
Example
The following defines a function named catch-me-if-you-can. This function accepts two number arguments and uses
vl-catch-all-apply to divide the first number by the second number. The
vl-catch-all-error-p function determines whether the return value from
vl-catch-all-apply is an error object. If the return value is an error object, catch-me-if-you-can invokes
vl-catch-all-error-message to obtain the message from the error object.
- At the AutoCAD Command prompt, enter the following code:
(defun catch-me-if-you-can (dividend divisor / errobj) (setq errobj (vl-catch-all-apply '/ (list dividend divisor))) (if (vl-catch-all-error-p errobj) (progn (print (strcat "An error occurred: " (vl-catch-all-error-message errobj))) (initget "Yes No") (setq ans (getkword "Do you want to continue? [Y/N]: ")) (if (equal (strcase ans) "YES") (print "Okay, I'll keep going") ) ) (print errobj) ) (princ) )Note: You can also add the example code to an existing or create a new LSP file. Then load the LSP file with the APPLOAD command.
- Enter the following code:
(catch-me-if-you-can 50 2)
The function returns 25.
- Enter the following code:
(catch-me-if-you-can 50 0)
The function issues the following prompt:
«An error occurred: divide by zero» Do you want to continue? [Y/N]:
If you enter y (or yes), catch-me-if-you-can indicates that it will continue processing. Try modifying this example by changing
vl-catch-all-apply to
apply. Load and run the example with a divide by zero again. When apply results in an error, execution immediately halts and *error* is called, resulting in an error message.The
vl-catch-* functions are especially important when you use ActiveX with AutoLISP. Many of the AutoCAD ActiveX automation methods are designed to be used in the “programming by exception” style. This means they either return useful values if they succeed, or raise an exception if they fail (instead of returning an error value). If your program uses ActiveX methods, you must prepare it to catch exceptions, otherwise the program halts, leaving the user at a Command prompt.Note: ActiveX is not supported on Mac OS and Web.
Существует
несколько различных ситуаций для обработки ошибок, с которыми
встречаются при программировании OpenDCL: обработка стандартных ошибок
AutoLISP, обработка ошибок ввода данных пользователем, и обработка
ошибок исполняемого модуля OpenDCL. Обработку стандартных ошибок
AutoLISP здесь рассматривать не будем.
Обработка ошибок ввода данных пользователем
Правильно
спроектированный графический дизайн пользовательского интерфейса
должен, по мере возможности, в первую очередь сам
по себе предотвращать ошибки ввода данных пользователем. OpenDCL
позволяет динамически отключать (или скрывать) определенные элементы
управления прямо во время выполнения программы, что дает возможность
перенастроить взаимозависимые элементы при изменении каких-либо
условий, апользователь смог совершить только действительно правильный
ввод. Поэтому хороший пользовательский интерфейс является первой линией
обороны против недопустимого ввода.
Обработка
ошибок пользовательского ввода в формах OpenDCL должна производиться с
помощью обработчиков событий отдельных элементов управления или же всей
формы в целом. Некоторые элементы управления, такие как текстовые
поля, поддерживают фильтры вводимых данных для предотвращения неверного
ввода. Использование таких элементов управления, какполя выпадающим со
списком или переключателей может заранее ограничить ввод пользователем
определенных значений. Для поддерживаемых форм событие CancelClose может быть использовано для проверки ввода в форме и предотвратить закрытие диалога если будет найден неверный ввод .
Ниже приведен стандартный сценарий использования события CancelClose :
(defun HighlightFormErrors ()
(if (CheckForFormInputErrors)
(progn
(dcl-MessageBox "Форма содержит недопустимые данные!" "Error" 2 4)
T
)
)
)
(defun c:Project1/Form1#OnCancelClose( Canceling /)
(and (/= 1 Canceling) (HighlightFormErrors))
Ошибки исполняемого модуля OpenDCL
Вызов встроенных функций OpenDCL может привести к двум типам ошибок: исключениям или функциональным сбоям.
Исключения указывают на ошибку в коде, например, при передаче в
фунцию неправильного типа аргумента, или аргумента с недопустимым
значением. Если сообщения OpenDCL не подавляются (смотри ПодавлениеСообщений),
то сообщение об исключении приводятся во всплывающем окне и описывает
расположение и характер исключения, вызванного ошибкой AutoLISP и
остановившего работу программы. В сообщении отображается имя функции и
индекс ее аргумента(нумерация с нуля), для которого произошло исключение.
Функциональные сбои обычно показаны как функция, возвращающая
NIL. Например, при попытке установить текущую выбор в списке на
несуществующий элемент списка возвращает значение NIL. Такие типы
ошибокпри желании можно обработатывать в коде, а в некоторых случаях просто игнорировать.
7.3. Список зарезервированных
идентификаторов
Следующие идентификаторы зарезервированы
для внутреннего пользования. Их нельзя использовать для имен переменных и
функций в пользовательских программах.
*Backtrace*
если переменная равна T, то, если встретилась
ошибка и не определена функция ERROR, печятается список имен в цепочке вызовов. Значение по
умолчанию Тю
*break* встроенная
переменная AutoLISP, управляющая условной обработкой
ошибок для AutoLISP c отладчиком. Если она равна Т,
задейетвуется цикл прерывания. Значение по умолчанию nil.
*Fastlink* если
переменная равна Т, то все обращения к функциям в скомпилированныхфункцияях
реализуется напрямую, поэтому невозможно отследить обращения в скомпилированных
функциях и в случае ошибки не будет видна бальшая часть трассы. Установка
значения переменной в nil обеспечивает обычую
трассировку, но при этом выполнение пойдет медленнее.Значение по умолчанию
равно Т.
*quietload* если
переменная равна nil, имена загружаемых функций
выводится на экран. Значение по умолчанию равно Т.
*user_break* если
функция с этим имнем, то она вызывается перед передачей управления
интерактивному отладчику.
*St, si* опции
пощаговой обработки, имеющиеся на уровне цикла прерывания при отладке.
*Bdc2, bdc4* внутренние
функции, используемые при загрузке скомпилированных функций.
*Reversip* встроенная
функция для быстрого реверсирования списка. Она необходима для поддержки
некоторых скомпелированных программ и дожна использоваться только для
внутренних целей.
Функции, описанные ранее:
Back_trace, break, debug, errset,
nextatom, signal_error, special, undebug, c:reset
Идентификаторы, возвращаемые функцией TYPE
для некоторых типов внутренних кодов:
Asubr, csubr, cympage, fsubr, agetb,
vsubr
8.Сообщения об ошибках
8.1 Собщения об ошибках стандартного
AutoLISP
Если AutoLISP встречает ошибку во время
вычислений, он печатает сообщиние в виде:
Error:текст
И обратную трассировку функций. Здесь текст – это опписание
ошибки. Ниже приведен список сообщений об ошибках, которые мгогут быть встречены
в процессе написания и отладки функкций AutoLISP.
ATOMLIST modified after function swap
ATOMLIST изменен после выгрузки
Функция модифицирует ATOMLIST. Это
не допустимо после выполнения функции VMON
AutoCAD rejected function
Неразрешенная функция
Аргументы, переданные в функцию AutoCAD,
были неверны или же в данном контексте сама функция неверна. Например, нельзя
пользоваться функциями GETxxx из функции COMMAND.
Bad argument type
Неверный тип аргумента
В функцию был передан неверный тип аргумента.
Bad association list
Неверный ассоциативный список
Список , переданный в функцию ASSOC ,
не состоит из списков “(ключ значение)”.
Bad entmod list
Неверный список описания примитива
Аргумент, переданный в функцию ENTMOD,
не состоит из списка данных примитива, возвращаемого функцией ENTGET.
Bad entmode list value
Список описания примитива содержит неверное значение
Один из подсписков переданных в функцию ENTMOD,
содержит неверное значение.
Bad formal argument list
Неверный список фоормальных аргументов
Выполняя функцию, AutoLISP обнаружил
неверный список формальных аргументов Возможно, это не функция, а список
данных.
Bad function
Неверное имя функции
Первый елемент списка – недопустимое имя функции. Возможно,
это имя переменной или число. Это сообщение может также указывать, что
функция неверно определена – не следует забывать требуемый список формальных
аргументов.
Bad list
Невероятный список
В функцию был передан неверно сформированный список.Это
может произойти, если действительное число начинается с десятичной точки; в
подсбных случаях число необходимо начинать с нуля.
Bad node.
Неверный тип элемента
Функция TYPE столкнулась с элементом
неверного типа.
Bad node type in list
Список содержит элемент невеноготипа
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание — внизу страницы.
Код без ошибок – возможно ли?
Коды, которые Вы будете разрабатывать, должны быть не только удобны и обладать приемлемым быстродействием, но и быть безошибочными. Что подразумевается под безошибочностью?
Все достаточно просто: в любом случае, после завершения работы функции (корректного или некорректного — это неважно) AutoCAD должен принять вид, который был установлен пользователем до вызова функции. Логические ошибки типа (/ 50. 0.) отследить просто, но как отследить ошибки пользователя? Например, нажатие [Esc] в самый неподходящий момент?
Есть несколько вариантов.
Вариант 1. Переопределение стандартного обработчика ошибок. В AutoCAD обязательно присутствует штатный обработчик ошибок, и имя ему — *error*. Функция принимает единственный параметр (текстовое сообщение об ошибке). А вот ее «внутренности» уже могут меняться. Так, например, обработчик ошибок в AutoCAD Architecture видоизменен самой Autodesk.
Переопределить обработчик можно — то есть написать собственную функцию *error*, которая будет выполнять те действия, которые требуются. Переопределить *error* можно и глобально (отдельной функцией), и локально — для определенной функции. Пример:
|
1 |
(defun lispru—func—1 (/ *error* fun_func—2) (defun *error* (msg) (defun fun_func—2 (/ *error*) (defun *error* (msg) (princ (/ 10. 0.)) (princ «\ncall (fun_func-2)») |
Если попытаться вызвать (lispru-func-1), мы получим в консоли:
|
1 |
call (fun_func-2) fun_func-2 error : divide by zero |
То есть такой обработчик заканчивает выполнение функции — обратите внимание, текст «(fun_func-2) finished» даже не пытается напечататься: срабатывает обработчик, прописанный в fun_func-2, и на этом выполнение кода заканчивается. А если продолжать все равно надо? В таком случае приходит на помощь вариант 2:
Использование функции vl-catch-*:
|
1 |
(defun lispru—func—2 (/ err fun_func—2) (defun fun_func—2 (/ err) (if (vl-catch-all-error-p (princ «\ncall (fun_func-2)») (if (vl-catch-all-error-p (princ) |
Теперь вызов (lispru-func-2) вернет
|
1 |
call (fun_func-2) |
Как видим, выполнение кода не прекращается ни при каких условиях. Что и где применять — в принципе, каждый решает сам, но лично я, проведя в свое время подобные эксперименты, окончательно и бесповоротно отказался от переопределения *error* и перешел на применение vl-catch-* функций.
В примерах я не давал переопределения глобального обработчика ошибок. Желающие поэкспериментировать могут сделать это самостоятельно.



