Forth и другие саморасширяющиеся системы программирования Locations of visitors to this page
Текущее время: Чт апр 18, 2024 07:22

...
Google Search
Forth-FAQ Spy Grafic

Часовой пояс: UTC + 3 часа [ Летнее время ]




Начать новую тему Ответить на тему  [ Сообщений: 4 ] 
Автор Сообщение
 Заголовок сообщения: Обработка исключений в форте
СообщениеДобавлено: Вт окт 28, 2008 13:38 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
Автор: mOleg
Дата публикации: 2008-10-28
публикуется впервые

Обработка исключений в форте

Введение

Начиная с ansi94 стандарта, в форте официально появился механизм, позволяющий ловить исключения, и некоторые ошибки, произошедшие в любом месте программы. Механизм включает в себя два оператора THROW и CATCH. Причем, THROW вызывает исключение, а CATCH "ловит" вызванное THROW исключение. В некоторых форт системах CATCH умеет ловить аппаратные исключения (например, SPF).

Пример

Приступая к рассмотрению работы механизма, рассмотрим следующий пример: необходимо прочитать содержимое файла в динамическую область памяти (HEAP), то есть необходимо выполнить следующие действия:

<pre>
: file>heap ( asc # --> addr # FALSE | ERROR )
открыть файл с именем заданным строкой asc #
определить размер открытого файла
выделить место под содержимое файла в хипе
прочитать содержимое файла в полученную память
закрыть файл
вернуть адрес где лежат данные и их длину или флаг ошибки
;
</pre>
Вроде все понятно, но надо не забыть, что файл может не открыться, размер может не определиться, места в хипе под файл может не оказаться, операция чтения может не удастся. При этом все ресурсы должны быть освобождены правильно. То есть, если любая операция после открытия файла окажется неуспешной, файл обязательно должен быть закрыт, если после успешного выделения памяти операция чтения файла не удастся, необходимо освободить и эту память и кроме того не забыть закрыть файл.
Данную задачу можно решать классическими методами, но при этом придется использовать множество операторов ветвления, причем классический подход не позволяет "ловить ошибки", произошедшие во вложенных словах, а так же аппаратные ошибки типа обращения к памяти по неверному адресу, или типа ошибок деления на нуль.

Устройство

В основе работы механизма исключений по сути лежит оператор GOTO, правда переход совершается не на фиксированный адрес, а на адрес хранящийся в определенном месте, в SPF это USER переменная с именем HANDLER, точнее эта переменная хранит адрес начала фрейма исключения, в котором хранится нужный адрес перехода.

Итак: THROW ( flag --> ) на входе у THROW находится флаг завершения операции, в зависимости от которого THROW принимает решение передавать ли управление на код, сохраненный в HANDLER или нет. Если flag отлично от нуля управление передается, иначе выполнение кода продолжается, при этом значение flag без изменений передается вызываемому обработчику. В коде обычно THROW используется следующим образом:

S" test.file" R/O OPEN-FILE THROW

напомню, что OPEN-FILE возвращает код завершения операции, и в случае невозможности открытия указанного файла возвращается код ошибки, который отличен от нуля. Но кроме этого THROW в случае отличного от нуля flag еще восстанавливает глубину наиболее важных стеков (как минимум это стек данных и стек возвратов, но могут быть и другие). Итак, если flag отличен от нуля, THROW выполняет переход на заранее определенное с помощью CATCH место, и производит этот переход из любого места программы.

Что же касается CATCH ( xt --> flag ) то синтаксически конструкции с ним выглядит следующим образом:

['] ИсполнимоеСлово CATCH IF ." у нас ошибка!" ELSE ." выполнение успешно!" THEN

Любая ошибка, передаваемая с помощью THROW, произошедшая в "ИсполнимоеСлово" в не зависимости от того, как она будет глубоко закопана в коде, приведет к переходу на точку после CATCH с флагом, определяющим тип ошибки, либо нолем, если слово было выполнено без ошибок. Говоря "любая ошибка" я немного утрирую - конечно же не любая, более того, некоторые типы ошибок ловить с помощью описываемого механизма бесполезно, например, переопустошение стека данных или возвратов.
Итак, CATCH возвращает флаг, который в последствии надо обработать или передать другому обработчику, поэтому можно встретить иногда и такой код:

['] ИсполнимоеCлово CATCH THROW

если ошибка в "ИсполнимоеСлово" не возникнет, то будет выполняться код после THROW, это означает, что обработчики исключений могут быть вложенными многократно (вложенность определяется количеством CATCH встреченным на пути программы). Кстати, замечу, что операционная система WINDOWS имеет аналогичный механизм, но вызывается он с помощью специальных API функций, а значит, работает медленнее встроенного в форт. Аппаратные же исключения типа ошибок деления на ноль в любом случае ловит операционная система, поэтому их обработка ведется значительно медленнее.

Решение

Ну, что же, вернемся к примерам, для начала рассмотрим более простую часть примера, а именно, открытие и правильное освобождение файла:
<pre>
\ открыть файл, выполнить некую 'Работу' над ним,
\ по окончании этой работы освободить открытый файл.
: ПерваяЧасть ( asc # --> flag )
R/O OPEN-FILE DUP IF NIP EXIT ELSE DROP THEN \ --> fid
DUP >R ['] Работа CATCH \ --> fid flag
DUP IF NIP THEN R> CLOSE-FILE DROP ; \ --> flag
</pre>
В первой строчке пытаемся открыть файл, так как файл может и не быть открыт, то с помощью: DUP IF NIP EXIT пытаемся корректно выйти с кодом ошибки из слова, либо удалить: ELSE DROP THEN код успешного завершения операции, чтобы он не мешался. Так как на стеке данных из слова запросто может возвращаться произвольное количество параметров, надежнее положить fid на вершину стека возвратов, где он не будет мешаться, так как баланс стека возвратов соблюдается гораздо строже, чем стека данных. Итак, копию идентификатора открытого файла сохраняем на стеке возвратов, а на стеке данных это же значение передаем в нашу 'Работу', которая выполняет какой-то код, который может завершиться как успешно, так и не успешно. В случае успешного завершения 'Работы' CATCH возвращает 0, но fid не возвращает, в случае же неуспешного завершения 'Работы' баланс стеков сохраняется, но данные на вершине стека данных могут быть испорчены, поэтому одну ячейку с вершины стека данных приходится удалять: DUP IF NIP THEN , а fid файла, который необходимо закрыть при любом исходе операции 'Работа' забирается с вершины стека возвратов, где он лежит нетронутым: R> CLOSE-FILE DROP - и тут мы не контролируем успешность закрытия файла, по крайней мере, это обычная ситуация, относительно безопасная, хотя, конечно, после CLOSE-FILE можно поставить THROW, и тогда сработает более глубоко закопанный обработчик СATCH.
<pre>
: Работа ( fid --> asc # FALSE | ERROR )
DUP FILE-SIZE THROW
0 <> THROW
\ --> fid size
DUP ALLOCATE THROW
DUP >R ['] Копировать CATCH
DUP IF NIP R> FREE DROP THROW THEN ;
</pre>
Итак, в слове 'Pабота' THROW может быть вызван в четырех возможных случаях:
- если нельзя определить размер файла;
- если файл больше адресуемой процессором памяти;
- если система не может выделить память под весь файл;
- если слово 'Копировать' почему-то не сработало.
Слово же 'Копировать' мы создаем вынужденно, так как обязательно необходимо в случае неуспеха копирования вернуть память системе.
<pre>
: Копировать ( fid size addr --> asc # )
2DUP 2>R ROT SWAP READ-FILE THROW
R@ <> THROW \ прочитано не столько, сколько просили
R> R> ;
</pre>
И опять две возможных проблемы:
- если файл не может быть прочтен по какой-либо причине;
- если прочитанный размер не совпадает с размером файла.
И опять оказалось удобно использовать стек возвратов для хранения промежуточных данных.

Выводы

С помощью рассмотренного механизма CATCH THROW можно ловить различные исключения и некоторые ошибки, но выглядит это громоздко и не очень, на первый взгляд, удобно. Механизм CATCH THROW не был придуман для форта, а просто импортирован (на уровне идеи и синтаксической конструкции) из языка высокого уровня (какого сказать сложно). Тем не менее, замены предложенному механизму в форте не имеется, по крайней мере на уровне последнего распространенного стандарта языка Форт.
Описанный механизм позволяет корректно освобождать различные ресурсы, но часто встает вопрос, где хранить промежуточные данные, обычно для этих целей из соображений Реентерабельности кода выбирают стек возвратов (возможен вариант с USER переменными, но это расход, как пространства имен, так и USER области потока; кроме того, не возможен рекурсивный вызов таких слов). Описанный механизм не позволяет исправлять все возможные ошибки, особенно, ошибки переопустошения стеков.
Существуют и другие аналогичные механизмы, например TRY TRAP FINALLY , которые так же позаимствованы у других языков. К сожалению рожденных в среде форта подобных механизмов я не встречал.


Последний раз редактировалось mOleg Вт окт 28, 2008 20:09, всего редактировалось 1 раз.

Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Вт окт 28, 2008 19:58 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
True-grue подсказал англоязычную статью CATCH and THROW посвященную обработке исключений в форте (перевод).
и еще немного на тему обработки исключений:
EXTENSION OF THE EXCEPTION HANDLING MECHANISM M.L.Gassanenko


Последний раз редактировалось mOleg Сб ноя 01, 2008 22:18, всего редактировалось 3 раз(а).

Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Вт окт 28, 2008 20:02 
Не в сети

Зарегистрирован: Вт май 09, 2006 12:31
Сообщения: 3438
Благодарил (а): 5 раз.
Поблагодарили: 16 раз.
Цитата:
где он не будет мешаться, так как баланс стека возвратов соблюдается гораздо строже, чем стека возвратов

нужно поправить

Цитата:
К сожалению рожденных в среде форта подобных механизмов я не встречал.

А на что это должно было бы быть похоже :?:

_________________
понимаю некоторую бестолковость некоторых вопросов


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Вт окт 28, 2008 20:12 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
вопрос писал(а):
нужно поправить

спасибо, подправил.

вопрос писал(а):
Цитата:К сожалению рожденных в среде форта подобных механизмов я не встречал.
А на что это должно было бы быть похоже

А кто его знает, просто есть некое ощущение инородности, хотя нельзя сказать, что это ощущение мешает успешно пользоваться ;)

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 4 ] 

Часовой пояс: UTC + 3 часа [ Летнее время ]


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5


Вы не можете начинать темы
Вы можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
phpBB сборка от FladeX // Русская поддержка phpBB