А можно и вообще без исключений обойтись.
Обработчики исключений работают хорошо только в однородной среде. Но стоит скрестить библиотеку на одном языке и прогу на другом языке - как сразу начинается моя-твоя-непонимать...
У меня была простая идея реализации (для x86) обработки исключений - внутри блока - компилятор знает где происходит исключение (оператор raise). Так же исключения могут передаться из вызываемых функций. Тут делаем так: если функция отрабатывает без исключения, то при возврате сбрасывает флаг cf в ноль и возвращает результат как обычно, если функция не обрабатывает исключение, то она устанавливает флаг cf в единицу, а в регистр eax записывает код исключения (или указатель на объект исключений) и возвращает управление. В вызывающем коде после вызова ставиться условный переход на обработчик исключения jc _handler.
_handler для блока try/finally
- Код: Выделить всё
_handler:
push eax ; сохраняем объект-исключение (или можно использовать переменную)
<код блока finally>
pop eax ; восстанавливаем объект-исключение
stc ; устанавливаем флаг cf в 1
ret
_handler для блока try/except
- Код: Выделить всё
_handler:
<код блока except>
jmp _continue ; возвращаемся к коду после блока try/except
Если в функции нет блока try/finally/except, то вставляется простой код
- Код: Выделить всё
_handler: ret
Т.е. уже установленный флаг cf и регистр eax передаются далее вверх по цепочке вызова.
Оператор raise Exception.Create:
- Код: Выделить всё
call Excpetion.Create ; в eax указатель на объект-исключение
stc ; устанавливаем флаг cf
jmp _handler ; переходим к обработчику
Кто-то заметит в этой схеме недостаток - не обрабатываются аппаратные исключения (например деление на ноль, и чтение недопустимого адреса и т.п.). А может их лучше не допускать? Ведь аппаратное исключение есть следствие кривых рук программиста... Зато будет работать в любой ОСи, т.к. не опирается ни на какие функции ОСи...
А для согласования кода на разных языках, нужно добавить как минимум директиву no_exception, типа как в C++ у функции можно дописать throw(), что означает, что данный код не передает никаких исключений. И если вы попытаетесь передать исключение, то компилятор поругает вас ошибкой компиляции... И требовать чтобы все экспортируемые функции использовали этот флаг или определяли его автоматически...