Я пытаюсь исправить обработку ошибок в моем интерпретаторе postscript, и мне трудно найти способы выполнения обработчиком, когда один из стеков заполнен.
Используемая мной процедура обработчика уровня postscript - это «стандартная» процедура, описанная в Frank Merritt Braswell, Inside Postscript.
/.error {
//$error exch /errorname exch put
//$error exch /command exch put
//$error /newerror true put
//$error /errorname get /VMerror ne {
//$error /ostackarray get null eq {
//$error /estackarray 250 array put
//$error /ostackarray 6000 array put
//$error /dstackarray 30 array put
} if
count
//$error /ostackarray get exch 0 exch getinterval astore
//$error exch /ostack exch put
//$error /dstack //$error /dstackarray get dictstack put
//$error /estack //$error /estackarray get execstack
dup length 2 sub 0 exch getinterval put
//$error /ostack get aload pop
} if
//$error /initializing get {
handleerror
} if
interrupt
} def
Таким образом, ему требуется место в стеке операндов (для словаря $ error, имен и прочего) и в стеке выполнения (для тел процедур, если они выполнены). Так что, если какой-либо из стеков переполнен, откуда это место должно появиться?
Сначала я попытался решить задачу execstackoverflow, поскольку execstack использует меньше операторов, чем стек операндов. Я определил размер буфера
#define ERRDEPTH 5 /*space reserved on execstack for error handling*/
которые все операторские функции "exec" добавляют к проверке пробела. Например. вот оператор exec
.
void Aexec(state *st, object x) { (void)st;
if ((tes-es)+1+ERRDEPTH >= ESSIZE) error(st,execstackoverflow);
pushe(x);
}
И тогда цикл интерпретатора проверяет наличие гораздо меньшего размера (поэтому он не вызывает даже больше ошибок при попытке запустить обработчик).
bool eval (state *st) {
...
/* room to work? */
if ((tes-es) + 2 /*+ ERRDEPTH*/ > ESSIZE) error(st,execstackoverflow);
...
Но это не сработает (SEGFAULT), пока я не очищу некоторое пространство в обработчике ошибок уровня C, как раз перед тем, как он выталкивает (планирует) обработчик PS в execstack.
...
if (e == execstackoverflow) { /* make some room! */
(void)pope(); (void)pope(); (void)pope(); (void)pope(); (void)pope();
(void)pope(); (void)pope(); (void)pope(); (void)pope(); (void)pope();
}
...
Но теперь я выбросил ребенка с водой! Эти записи на вершине стека могут быть просто важной информацией для исправления ошибки, и я просто выбросил их в пропасть.
Кто-нибудь может предложить лучший способ сделать это?