Ловля исключений из цикла
Я пытаюсь написать слово Forth, которое бросит все элементы в стеке. Я использую довольно тупой метод, выполняя бесконечный цикл с помощью drop и ловя ошибку, когда не удается выполнить drop, поскольку стек пуст.
Мои слова определены так:
( Infinite drop loop)
: droploop begin drop true while drop repeat ;
( Experimental catch with a single drop)
: dropcatcher ['] drop catch drop ;
( Like dropcatcher, but with 'droploop' instead of 'drop')
: dropall ['] droploop catch drop ;
Когда я запускаю droploop, я получаю сообщение об ошибке, как и ожидалось, и после выполнения стек пуст. Когда я запускаю dropcatcher, он сбрасывается, если стек не пуст, а если стек пуст, он ничего не сообщает. Когда я запускаю dropall, я получаю все остальное в стеке.
Это выглядит так:
2 3 4 5 6 7 8 9 10 dropall.s <9> -1 3 -1 5 -1 7 -1 9 -1 ок
Я ожидаю, что dropall просто очистит стек без жалоб, потому что droploop и dropcatcher, похоже, работают сами по себе, но, увы, я не понимаю, почему dropall не работает.
Почему dropall работает иначе, чем droploop и dropcatcher? Или что я тут не так делаю?
1 ответ
Когда droploop
выдает ошибку, скорее всего это вызовет ABORT
или же -1 THROW
, который по определению очищает стек данных. Так что вполне может быть, что droploop
не удаляет нужное количество элементов стека до обнаружения ошибки, но системный обработчик исключений делает это за вас.
Когда я бегу droploop
Сам он либо вылетает, либо зависает. Казалось бы, это подтверждает мою теорию, что существует серьезный недостаток стека.
Что касается состояния стека после dropall
я думаю, что gforth, возможно, не обнаружит переполнение стека в нужное время, а то, что вы видите, это какой-то полуслучайный мусор. Следовательно, это то, что droploop
оставляет в стеке перед вызовом ABORT
,
Примечание: ваш droploop
отбрасывает два элемента стека за каждую итерацию, что может или не может быть тем, что вы хотели. Также используйте again
для бесконечного цикла вместо true while
, Т.е. : droploop begin drop again;
Конечно, лучший способ очистить стек
: clear depth 0 ?do drop loop ;
или же
: clear begin depth while drop repeat ;
или же
: clear sp0 sp! ;