Советы по игре в гольф в Postscript?


14

В качестве одного из менее популярных языков трудно найти литературу по авангарду хакерства постскриптума. Итак, какие открытия сделали игроки в гольф, чтобы использовать стековую модель (или другие особенности) для преодоления врожденного многословия Postscript?


Нашли несколько внешних страниц: sites.google.com/site/codegolfingtips/Postscript
luser droog

Ответы:


3

Встроенный декодер

Программа Postscript обладает уникальной (?) Способностью считывать текст своей программы в виде данных. Это , как правило , используется imageоператор , который принимает конверсию-процедуру передачи данных в качестве входных данных, и эта процедура часто использует currentfileследуют readline, readstringили readhexstring. Но если смотреть по-другому, imageэто просто еще один оператор цикла, поэтому любой цикл может читать вперед . Примером является эмулятор линейного принтера из Зеленой книги.

С использованием token оператора вызывает сканер для файла или строки, вытягивая число или пробел - (или иначе -: см. Другой ответ) - неограниченное имя.

Простой PS-интерпретатор в PS:

{currentfile token not {exit} if dup type /arraytype ne {exec} if }loop

Бинарный оператор струнного декодера

Поскольку я не могу заставить работать необработанные двоичные токены (см. Другой ответ), я использовал идею «встроенного декодирования», чтобы использовать механизм двоичных токенов для упаковки кода в 8-битные строки, а затем манипулировать и разбирать команды из строки на лету .

/.{
    <920>  % two-byte binary-encoded name template with 0x92 prefix
    dup 1 4 3 roll put  % insert number into string
    cvx exec  % and execute it
}def
/${
    //.   %the /. procedure body defined above
    73 .  %"forall" (by code number)
}def

.Процедура занимает несколько из стека и вставляет его в качестве второго байта в строке два байта, первый байт являются префикс байтами для двоичных маркеров, который определяет исполняемое имя системы. Мы сохраняем байт в шестнадцатеричной строке, используя правило сканера, согласно которому нечетное число полубайтов в шестнадцатеричной строке дополняется дополнительным полубайтом 0, поэтому 3 шестнадцатеричных полубайта дают 2-байтовую строку. Затем строка помечается как исполняемая и execвызывается, с помощью которой запускается сканер, выдается имя требуемой исполняемой системы, а затем загружается имя и выполняется оператор. Это $делается для каждого байта строки в стеке, используя .процедуру дважды , один раз в качестве тела цикла, а затем для выполнения оператора цикла forallпо номеру.

Более компактно эти процедуры выглядят так:

 /.{<920>dup 1 4 3 roll put cvx exec}def/${//. 73 .}def
%123457890123456789012345678901234567890123456789012345
%        1         2         3         4         5

Таким образом, 55 символов покупают двоичные строки токенов. Или, 6 (может быть 7, если прекратить его с пробелом) символами, вы можете загрузить библиотеку G с (G)runкоторой определяет .и , $как указано выше (+ несколько других , чтобы расширить диапазон ASCII-кодов достижима).

Далее проиллюстрирован мой ответ на кроссворд .


1
На самом деле, если постскриптум находится в закодированной форме, то это требует от вас особой осторожности при сравнении. В частности, если вы смотрите на операторах, вы должны разобрать его в качестве маркеров , а затем сравните лексемы имя к целевому значению.
AJMansfield

2

Когда генерация графического вывода и вывода на консоль не имеет значения, используйте =вместо pop.


2

Заменить шестнадцатеричные строки на ASCII85

Возможно старые новости, но я только что узнал. :)

Вы можете сделать это, используя интерпретатор postscript в интерактивном режиме с фильтром кодирования и вырезанием и вставкой. Но я собираюсь показать, как использовать, dcчтобы сделать это «вручную».

Итак, вот шестнадцатеричная строка. Разобьем его на 4 байта.

95 20 6e d8   d0 59 49 35   50 74 ba c5   08 2d

Запуская dc, мы вводим их как 32-битные (без знака) числа с порядком байтов в порядке байтов. Затем mod -off base-85 цифр (должно быть 5, пока вы не получите 0).

0> постоянный ток
16i
95206ED8
искусственный интеллект
d85% N85 /
82
d85% N85 /
83
d85% N85 /
82
d85% N85 /
78
d85% N85 /
47
d85% N85 /
0                    

Заполнение последнего фрагмента 00 00, приводит к (десятичному), пропуская то же количество байтов, которое мы дополнили.

47 78 82 83 82   66 81 72 79 83   25 72 82 25 69  2 53 30 [2 53]

Добавьте 33, чтобы перейти в диапазон для печати ASCII и пуф! Ascii85.

80 111 115 116 115 99 114 105 112 116 58 105 115 58 102 35 86 63,
который декодирует в: Postscript: is: f # V? %%% Oops! должен сказать «весело»! Я облажался где-то. :)

Оберните это в <~... ~>, и PostScript уровня 2 может получить доступ к 8-битным данным, дешевле чем шестнадцатеричный.


2

Вот быстрый способ: оберните несколько определений, [...>>beginчтобы исключить ключевое слово def(nb. [- то же самое, что и <<).

 def def
[>>begin

Итак, помните: больше, чемтридва ... собираться вместе ! ;)


Разве не должно быть правило «больше двух»? Сравните /a 1 def/b 2 def/c 3 defс <</a 1/b 2/c 3>>begin. Нам нужно больше места для определения.
Томас В.

Вау. Я не думал об этом. Да, расчет нуждается в улучшении.
Люсер Дрог

На самом деле, это должно быть[/a 1/b 2/c 3>>begin
Томас В.

лицо ладонь. , , ,
Люсер Дрог

1
Это может не применяться, если вы называете что-то, что заканчивается на токене с самоограничением. В /a{pop 2 mul}defили \b[2 3]def, то defстоит только 3 -х символов, а не 4.
AJMansfield

2

В то время как большинство постскрипта операторов синтаксически идентификаторы (и , следовательно , должен быть пробела (или otherwise-) с разделителями), имена [, ], <<, и >>являются саморазграничны и сканер обнаружит их без вмешательства пространства. По той же причине вы не можете ссылаться на эти имена с обычным /literalсинтаксисом (например, /[это два токена: пустое литеральное имя, эквивалентное ()cvn cvlitи исполняемое имя, [эквивалентное ([)cvn cvx exec).

Чтобы переопределить эти имена, которые не могут быть упомянуты по имени, мы можем использовать строки, которые неявно преобразуются в имена при использовании в качестве ключей в словаре (удобно!).

Этот пример иллюстрирует злоупотребление этими операторами для выполнения арифметики.

%!
([)0 def
(])1 def
(<<){add}def
(>>){mul}def
 ]]<<]]]<<<<>> =
%1 1 add 1 1 1 add add mul = %prints 6

Также <<и [mark) все означают одно и то же.


Мой собственный интерпретатор постскриптума xpost также предоставляет правую фигурную скобку с некоторыми ограничениями. обсуждение


2
Кроме того, /завершает предыдущий токен, так что вам не нужно пробела перед ним.
Джефф Риди

1

Фактор многократного использования длинных имен операторов

Если вы уже используете <<>>beginсловарь, /?{}на переопределение накладываются постоянные накладные расходы в 4 символа. Таким образом, оператор длины n, повторенный N раз, приведет к изменению числа символов
(4 + n ) - ( N * ( n - 1)).

Установка этой формулы равной 0 дает уравнение точки безубыточности . Из этого мы можем решить для каждой переменной в терминах другой, давая
n = - ( N - 4) / (1 - N ) и
N = (4 + n ) / ( n - 1).

Нет, мы можем ответить на такие вопросы, как «Для скольких видов использования« печати »стоит сокращаться?» n = 5, поэтому N = 9/4. Возьмите потолок, так как вы не можете эффективно назвать печать 1/4 раза. Итак, 3. 3 использует. И действительно,

print print print
/P{print}p p p

( <<>>beginконечно, если вы уже заплатили за активацию определения).

Разумеется, двоичные токены вызывают подобные споры, давая вам первые 255 имен из таблицы системных имен в виде 2 байтов: 0x92, 0x ??. И двоичные токены также являются саморазграничивающими, не требующими пробелов до или после, поскольку старший бит первого байта находится вне диапазона ascii.


1

Двоичные токены

Для окончательной на молнию программы PostScript , что последний рубеж двоичные маркеры , которые позволяют удалить длинные имена операторов полностью, за счет более не имеющий ASCII-чистой программы.

Итак, начиная с компактного блока кода PostScript

[/T[70{R 0 rlineto}48{}49{}43{A rotate}45{A neg rotate}91{currentdict
end[/.[currentpoint matrix currentmatrix]cvx>>begin begin}93{. setmatrix
moveto currentdict end end begin}>>/S{dup B eq{T begin exch{load exec}forall
end}{exch{load exch 1 add S}forall}ifelse 1 sub }>>begin moveto 0 S stroke

Мы ищем все имена в конце PLRM (Приложение F, стр. 795-797)

appearance
in
vim    dec  meaning

<92>   146  'executable system name' binary token prefix
^A     1    add
^M     13   begin
^^     30   currentdict
'      39   currentmatrix
(      40   currentpoint
2      50   cvx
8      56   dup
9      57   end
=      61   eq  !)
>      62   exch
?      63   exec
I      73   forall
U      85   ifelse
d      100  load
h      104  matrix
k      107  moveto
n      110  neg
<85>   133  rlineto
<88>   136  rotate
§      167 stroke
©      169 sub

А затем введите их с префиксом 146(десятичного) байта. vim help для ввода произвольных байтов

Затем в vim сжатый файл можно набрать напрямую, поэтому:

[/ T [70 {R 0 ^V146 ^V133} 48 {} 49 {} 43 {A ^V146 ^V136} 45 {A ^V146 ^V110 ^V146 ^V136} 91 { ^V146 ^V30 ^V146 ^V57 [/. [ ^V146 ^V40 ^V146 ^V104 ^V146 ^V39] ^V146 ^V50 ] >> ^V146 ^V13 ^V146 ^V13} 93 {. ^V146 ^V156 ^V146 ^V107 ^V146 ^V30 ^V146 ^V57 ^V146 ^V57 ^V146 ^V13} >> / S { ^V146 ^V56 B ^V146 ^V61 {T ^V146 ^V13 ^V146 ^V62 { 73 146 57} { 146^V 146 ^V100 ^V146 ^V63}^V146 62^V^V^V^V^V62 { ^V146 ^V100 ^V146^V

... Вы должны ввести пробел здесь, чтобы завершить ^V -62 и начать 1, но вы можете сделать резервную копию и удалить его позже ...

1 ^V146 ^V1S} ^V146 ^V73} ^V146^V 85

... необходимо ввести пробел здесь, чтобы завершить ^V -85 и начать 1, но вы можете сделать резервную копию и удалить его позже ...

1 ^V146 ^V169} >> ^V146 ^V13 ^V146^V 107

... 3-я цифра 3-значного кода завершает ввод байта, поэтому следующее 0 здесь нормально, удобно ...

0 S ^V146^V 167

Который будет выглядеть на экране (в vim):

[/T[70{R 0<92><85>}48{}49{}43{A<92><88>}45{A<92>n<92><88>}
91{<92>^^<92>9[/.[<92>(<92>h<92>']<92>2>>
<92>^M<92>^M}93{.<92><9c><92>k<92>^^<92>9<92>9<92>^M}
>>/S{<92>8B<92>={T<92>^M<92>>{<92>d<92>?}<92>I<92>9}{<92>>
{<92>d<92>>1<92>^AS}<92>I}<92>U1<92>©}>><92>^M
<92>k0 S<92>§

Эту часто можно полностью опустить, если целью является просто показать картинку. Ghostscript рисует большинство вещей на экране без необходимости showpage.

¡    161   showpage

[ Это на самом деле не работает. Ghostscript дает мне undefinedи syntaxerrorза эти жетоны. Может быть, есть какой-то режим, который мне нужно включить. ]


Может быть, это что-то об этой программе. Онлайн Уплотнитель не нравится, либо.
Люзер Дрог

1

Изменить отрицательные броски на положительные

Отрицательные броски всегда можно заменить положительными бросками .

3 -1 roll
3 2 roll

5 -2 roll
5 3 roll

Что является более эффективным 3 -1 rollили 3 2 roll? В моей ментальной модели первое должно быть более эффективным, потому что это занимает всего один ход. Правильна ли моя ментальная модель?
поцелуй мою подмышку

Честно говоря, я не уверен. Вот моя реализация , где все отрицательные броски конвертируются в положительные в качестве первого шага. Я думаю, что все равно потребуется как минимум 2 хода (переместить 3-е значение вверх , переместить 3 значения вниз ) с плоской реализацией стека. Но мой стек сегментирован, поэтому доступ осуществляется через вызовы функций для управления сегментами; так что, безусловно, есть более эффективные способы реализации, чем я. ... Теперь я вижу одну вещь: я должен проверить стек в потоке вне циклов.
Люсер Дрог

1
Исходный файл был перемещен с момента моего последнего комментария. Вот моя реализация на rollоператора.
Люсер Дрог

0

Используйте мою библиотеку G

https://github.com/luser-dr00g/G

Это текстовый файл. Без расширения, для кратчайшего синтаксиса, чтобы загрузить его.

Это позволяет эту программу Sierpinksi Triangle с 20 символами

[48(0-1+0+1-0)49(11)43(+)45(-)/s{dup
0 eq{exch{[48{1 0 rlineto}49 1 index
43{240 rotate}45{120 rotate}>>exch
get exec}forall}{exch{load
exch 1 sub s}forall}ifelse 1 add}>>begin
9 9 moveto(0-1-1)9 s fill

переписать в 151 байт как

3(G)run $
{A - B + A + B - A}
{B B}

{A - B - B}7{[ex{du w{(>K?\2u)$}if}fora]}rep
cvx[/A{3 0 rl}/B 1 in/-{120 rot}/+{-120 rot}>>b
100 200(k?B9)$ showp

рабочий файл с комментариями

Использование функции сокращенных системных имен 1(G)runполностью снимает бремя длинных имен операторов. Имя оператора должно быть достаточно длинным, чтобы отличить его от других.

Так

  • add становится ad
  • mul становится mu
  • index становится i
  • и т. д.

Используйте Приложение F PLRM для стандартной таблицы имен операторов.

И функция Строки Оператора доступна, даже если сокращенные имена не выбраны. Голая библиотека имеет «базовый уровень», выбранный простым добавлением (G)runбез дополнительных украшений.

Базовый уровень включает новую функцию, .которая принимает целочисленный код для оператора (то же самое Приложение F, упомянутое выше) и выполняет его.

Новая функция $перебирает строку и вызывает .каждую. Таким образом, код ascii напрямую выбирает оператора по номеру.

Новая функция @позволяет вам добраться до нижней части таблицы в Приложении F, обрабатывая символ пробела (Ascii 0x20) как 0.

Новая функция #позволяет вам подняться дальше в таблицу, сначала добавив 95 (0x5F), чтобы символ пробела 0x20 обрабатывался как 127 (0x7F), самый следующий код после последнего печатаемого символа ascii ~126 (0x7E).

Две новые функции !позволяют получить доступ к глубоко вложенной структуре массивов и / или диктов с помощью массива индексов / ключей, а не утомительных выражений многих getput) операторов.

(G)run 7 символов покупает базовый уровень.

1(G)run 8 символов покупает это И сокращенные системные имена.

3(G)run $9 символов сразу начинают блок неявной процедуры сканируя исходные строки до следующей пустой строки, и определяя первую строку как вызываемую процедуру A, следующая строка определяется как вызываемая процедура Bи т. Д. Это должно удалить большинство из defs, необходимых для определения много вещей, без необходимости оборачивать их в словарь, и даже не давать им явно имена.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.