Подтвердить что ты не робот

Отладка PostScript

Как я могу выполнить отладку в PostScript? Я могу использовать GhostView/GhostScript в Linux, но я не могу просмотреть стек, словари и т.д.

4b9b3361

Ответ 1

минимальный отладчик

Я только что обнаружил действительно полезный хак.

<<
/break{ /hook /pause load store }
/cont{ /hook {} store }
/doprompt{
    (\nbreak>)print
    flush(%lineedit)(r)file
    cvx {exec}stopped pop }
/pause{ doprompt }
/hook{}
>> begin

Это 8-строчный EMBEDDABLE отладчик. Я приготовил это для своего эмулятора 8086. Поместите hook в основной цикл, вставьте break в процедуру, чтобы вызвать паузу на следующем хуке (я поместил его в подозрительные процедуры OPCODE, и хук - это то место, где разрыв получает свой первый эффект). Хук-вызовы pause и pause звонки doprompt что дает вам однострочное приглашение "break>". Печатание cont здесь очистит крючок и продолжит вращаться, не делая никаких пауз, пока не встретится другой break. Вы также можете проверить значения и выполнить код в doprompt строке, но выполнение nb возобновляется, когда вы doprompt Enter, поэтому, если вам нужны дополнительные строки, вызовите doprompt или pause в конце строки. Ошибки игнорируются при выполнении команды (вы не хотите, чтобы отладчик аварийно завершал работу программы, это было бы глупо!). Я полагаю, я мог бы объединить паузу и допромпт и исключить имя; но цель здесь не в эффективности машины, а в четком наборе понятий: этот код, чтобы вообще быть полезным при отладке другого кода, должен легко сканироваться и проверяться.

Как это отладчик, он просто читает строку?!

Помните, что у вас есть = и == для изучения значений. forall и get бюст до массивов и прочее. Чтобы по-настоящему выяснить, где вы находитесь, countexecstack array execstack == для удобочитаемого дампа всего кабачка. То есть обратная трассировка текущей позиции в стеке выполнения, которая содержит хвосты всех частично выполненных процедур и файлов, ожидающих возобновления при возвращении текущего кадра.


"Printf"

Существует довольно много отладок, которые можно выполнить без отладчика как такового, просто используя инструментальную программу (так сказать, добавляя printf s).

Только сейчас я столкнулся с ошибкой, с которой мой отладчик не смог мне помочь, потому что сам отладчик зависал из-за слишком умных вещей, таких как

/E [ 0 0 10 ] def %eye point
/crackE { % set pointers into E
    /ex E 0 1 getinterval cvx def
    /ey E 1 1 getinterval cvx def
    /ez E 2 1 getinterval cvx def
} def crackE

Таким образом, фактическая ошибка, которую я расследовал, была

GPL Ghostscript 8.62 (2008-02-29)
Copyright (C) 2008 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Error: /stackunderflow in --forall--
Operand stack:
   --nostringval--
Execution stack:
   %interp_exit   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   false   1   %stopped_push   1905   1   3   %oparray_pop   1904   1   3   %oparray_pop   1888   1   3   %oparray_pop   1771   1   3   %oparray_pop   --nostringval--   %errorexec_pop   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   0.238095   0.047619   0.952381   --nostringval--   %for_real_continue   68.5714   17.1429   360.048   --nostringval--   %for_real_continue   --nostringval--
Dictionary stack:
   --dict:1151/1684(ro)(G)--   --dict:0/20(G)--   --dict:121/200(L)--   --dict:13/20(L)--   --dict:1/2(L)--
Current allocation mode is local
Last OS error: 2
Current file position is 3241
GPL Ghostscript 8.62: Unrecoverable error, exit code 1

И все, что мне действительно нужно знать, это то, что это --nostringval-- вещь в стеке операндов на самом деле.

Так что я положил это в начале программы

/forall { pstack()= forall } bind def

и запустить его снова и сейчас

{MO matmul 0 --get-- --aload-- --pop-- proj action}

Error: /stackunderflow in --forall--
Operand stack:
   --nostringval--
...

Непосредственно перед ошибкой есть последний стековый дамп (использующий ==), который говорит мне, что у меня в теле процедуры отсутствует ее набор данных.

pstack немного тупой по сравнению с чем-то вроде этого

/args { dup 1 add copy -1 1 { -1 roll ==only ( ) print } for } def
/forall { 2 args (forall)= forall } bind def

что было бы более полезно для отслеживания ошибочных данных в явно работающем коде. Это также способ, которым очень ранние версии Distiller создавали оптимизированные файлы .ps, определяя только операции рисования, чтобы выгружать себя, остальная часть вычислений "отгоняется".

Некоторые хитрости

()= %print a newline
=string %built-in 128-byte buffer used by = and ==
/object =string cvs print %convert object to string and print without newline
/stack { count dup 1 add copy { = } repeat pop } def % this is the code for the stack operator
66 (#) dup 0 3 index put print %m non-destructively print a "char"

[Я написал "=" вместо "стек" здесь ранее. Плохая ошибка Изменение: добавлен отсутствующий pop в /stack.]


ошибочный взлом

Другой способ исследовать ошибку - изменить обработчик ошибок. Чтобы исследовать описанную выше ошибку /stackunderflow я мог бы использовать

errordict/stackunderflow{dup == /stackunderflow signalerror}put

вместо того, чтобы специализировать forall. Чтобы узнать об этом довольно загадочном аспекте приписки, читать на errordict stop и stopped. И в интерактивном режиме errordict{exch =only ==}forall на errordict{exch =only ==}forall. signalerror ошибка в ghostscript называется .error в интерпретаторах Adobe. Его задача - сделать снимки стеков, а затем вызвать stop чтобы вытолкнуть стек exec. Таким образом, dup == здесь и pstack выше по сути являются одним и тем же "моментом" ошибки до stop. Ваш интерактивный сеанс (и предыдущая программа в обычном режиме gs) заключены в скобки глубже в стеке exec с эквивалентом //your-program stopped { handleerror } if. Именно handleerror использует моментальные снимки (после handleerror программы) для печати отчета об ошибке с неинформативными стеками.

Существуют замены, которые вы можете найти для handleerror который вы можете (ehandle.ps)run в начале программы с ошибками, чтобы создать различные стилизованные отчеты об ошибках.

Проверить $ ошибку

Я только что обнаружил это, перечитывая мои примеры здесь. Вы также можете исследовать стеки после ошибки, если переводчик все еще дает вам подсказку. Информация об ошибках сохраняется в словаре $error, включая снимки стеков.

GS>[ 1 2 3 ] [4 5 6] bogus
Error: /undefined in bogus
Operand stack:
   --nostringval--   --nostringval--
Execution stack:
   %interp_exit   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   %loop_continue   --nostringval--   --nostringval--   false   1   %stopped_push   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--
Dictionary stack:
   --dict:1168/1684(ro)(G)--   --dict:0/20(G)--   --dict:77/200(L)--
Current allocation mode is local
Current file position is 24
GS<2>

GS<2>$error{pop ==}forall
/dstack
/recordstacks
/globalmode
/newerror
/.nosetlocal
/estack
/errorinfo
/.inerror
/SubstituteFont
/position
/binary
/ostack
/command
/errorname
GS<2>$error/ostack get ==
[[1 2 3] [4 5 6]]
GS<2>

Конечно, здесь объекты все еще были в стеке. Но здесь есть $error. Не пытайтесь это сделать: $error ===. TMI.

Одна очень полезная часть информации, которую вы можете получить из $error - это симпатичная печать /estack, копии стека выполнения в точке ошибки.

PS<3>$error /estack get ==
[ --quit--{ pop --quit--} false { quitflag false --def---dict- /
execdepth 2 --copy----get--1 --sub----put----end---dict- /doclose false 
--put--interrupt } --loop----cvx--[ /quitflag false --def---dict- /
newerror false --put--/prompt --load----stopped--{ (
Error during prompt execution
)--print--handleerror --exit--} --if--{ 
mark /stmtfile (%statementedit)(r)--file----def--} --stopped--{ --
cleartomark---dict- /newerror --get--{ -dict- /errorname --get--/
undefinedfilename --ne--{ handleerror } --if---dict- /newerror false --
put----exit--} --if--} { --pop--stmtfile --end--{ --cvx----exec--} --
stopped---dict- --begin--{ handleerror stmtfile --closefile--} --if--} 
--ifelse--checkquit ] { checkquit } { -dict- --begin--{ handleerror 
stmtfile --closefile--} --if--} false -file- -file- -file- --repeat----
cvx--[ randcurve randwidth randcolor stroke ] 1 { flushpage newpath } { 
newpath } --forall----cvx--[ dup length 2 gt { [ currentcolordict DEVICE
 /nativecolorspace get get exec counttomark 2 add -1 roll DEVICE dup /
FillPoly get exec pop pstack ()= flushpage } { pop } ifelse ] [ ] { pop 
pstack ()= flushpage } { x_max width 0.50 add def (
intersect polygon edges with scanlines)= /P poly poly length 1 sub get 
def [ poly { Q exch def x_max miny floor cvi 0.50 add 1 maxy ceiling cvi
 0.50 sub { 1 index exch -0.50 1 index 4 2 roll P aload pop Q aload pop 
.intersect { 2 array astore exch } if } for pop /P Q def } forall ] (
sort scanline intersection list)= dup { 1 index 1 get 1 index 1 get eq 
{ exch 0 get exch 0 get lt } { exch 1 get exch 1 get lt } ifelse } qsort
 (set pixels on each scanline)= aload length 2 idiv { exch aload pop 3 2
 roll aload pop /USEDRAWLINE where { pop r g b 7 3 roll currentdict 
DrawLine } { pop 3 2 roll exch 1 exch dup width ge { pop width 1 sub } 
if { r g b 4 3 roll 2 index currentdict PutPix } for pop } ifelse } 
repeat end } --forall----cvx--[ aload pop .maxmin ] [ [ 16 154 ] [ 16 
154 ] ] { pop .maxmin } ] 
PS<3>

Теперь большая часть этого, вероятно, будет бредовой, а несколько лучших могут даже не читаться. Этот вывод взят из моего собственного интерпретатора postscript, который находится в стадии разработки, и все объекты имеют полный доступ. Но не смотрите на верх. Посмотрите на дно. Самый последний элемент массива является самым верхним элементом стека. Кусок кода, который был бы следующим, если бы /command не пошла и не была выполнена /errorname. Этот небольшой фрагмент постскриптума может помочь вам найти источник проблемы. В моем случае выше, мне нужно найти в моем источнике вызовы .maxmin перед которыми .maxmin pop перед... независимо от ошибки.

позвонить executive чтобы получить подсказку

Если у вас есть сеанс последовательного или telnet с переводчиком на принтере, вы можете набрать executive и нажать несколько раз. Это может не повторять исполнительные письма при executive. Не бойтесь, но пишите правильно. Это должно дать вам приветствие и подсказку.

С ghostscript запуск программы без аргументов даст вам тот же вид исполнительной сессии. Затем вы можете (yourfile)run и вы все равно должны получить сообщение об ошибках, позволяющее вам проверить $ error, как описано выше.

Если это не сработает, вы можете попробовать запустить executive дважды. Это добавляет дополнительный уровень обработки ошибок (еще один stopped {handlerror} if в стеке exec). Это может помочь в поиске более странных ошибок.

пошаговый отладчик

У меня есть пошаговый отладчик на уровне исходного кода, который должен работать в любом интерпретаторе PostScript, совместимом с уровнем 2.

Его также можно использовать для генерации трассировки стека, как показано в этом ответе на TeX.SE.

Ответ 2

Emacs включает инструменты PostScript. Он включает в себя инструменты для отправки интерпретатора postcript вашего выбранного в данный момент текста, а также вы можете вводить команды непосредственно в тот же интерпретатор, например, для запроса стека операндов или таких вещей.

Возможно, это не то, что вы ищете, потому что это может быть труднее использовать, чем вы готовы работать. Однако настройте правильно, с разными буферами для всех вещей, которые вы хотите контролировать, сценариев и макросов, чтобы делать что-то и т.д., И будет делать все, что вы хотите. Я не уверен, но в сети есть вещи, которые могут помочь вам настроить его.

EDIT: Основной способ, которым я использовал Emacs для отладки postscript, заключается в следующем: Я могу скопировать фрагменты программы из файлового буфера в буфер интерпретатора в качестве способа выполнить мою программу. Я также могу использовать его, чтобы рассказать мне о стеке операндов, используя команды для распечатки его содержимого и т.д. Я также могу добавить операторы отладки в код (например, dup == и т.д.), Который будет выводиться в буфер интерпретатора, потому что я не мог понять, как просматривать stdout, поскольку программа выполняется в других средах.

Ответ 3

В OS X 10.7.5 предварительный просмотр не дает мне никаких подробностей, когда он бомбит, но /usr/bin/pstopdf дает мне дамп стека для stdout и что там, где pstack тоже идет.

Если я открою файл pdf в предварительном просмотре, то при повторном просмотре после запуска pstopdf будет обновлен вид для вновь созданного pdf файла.

Это не хай-тек, но вы можете очень быстро итеративно.

Ответ 4

PS Alter - это инструмент для отладки postscript. В PSAlter откройте файл postscript, нажмите "Прогулка". установите скорость медленно. Вы можете увидеть текущий операнд, стек выполнения и словари. при выполнении файла.