Поради щодо гольфу в Postscript?


14

Як одну з менш популярних мов, важко знайти літературу про авангард поскриптських хакерів. Отже, які відкриття тут зробили гольфісти для використання моделі стека (або інших особливостей) для подолання притаманної багатослівності Postcript?


Знайдено кілька зовнішніх сторінок: 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

Напевно, стара новина, але я просто дізнався її. :)

Ви можете зробити це за допомогою інтерпретатора постскрипту інтерактивно з кодуючим фільтром та вирізати та вставити. Але я покажу, як dcце зробити, щоб зробити це «вручну».

Отже, ось шістнадцятковий рядок Ми розділили його на 4-байтні шматки.

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

Запускаючи постійний струм, ми вводимо їх як 32-бітні (непідписані) номери великого ендіанського байтового порядку. Тоді модифікація - відмінна база-85 цифр (має бути 5, поки ви не отримаєте 0).

0> DC
16і
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: є: f # V? %%% На жаль! слід сказати "весело"! Я кудись накрутив. :)

Згорніть його в <~... ~>, а Postcript Level-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. Нам потрібно більше пробілів для def.
Томас В.

Ого. Я цього не мав. Так, розрахунок потребує вдосконалення.
luser droog

Власне, це має бути[/a 1/b 2/c 3>>begin
Томас В.

обличчя-долоня. . . .
luser droog

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).

Ні, ми не можемо відповісти на запитання на кшталт: "Для скільки вживань" print "варто скоротити?" 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-чистої програми.

Отже, починаючи з ущільненого блоку коду постскрипту

[/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 для введення довільних байтів

Тоді в 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 { ^V146 ^V100 ^V146 ^V63}^V146 ^V73 ^V146 ^V57} { ^V146 ^V62 { ^V146 ^V100 ^V146 ^V62

... тут потрібно ввести пробіл, щоб скасувати ^V-62 та запустити 1, але пізніше можна створити резервну копію та видалити ...

1 ^V146 ^V1S} ^V146 ^V73} ^V146 ^V85

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

1 ^V146 ^V169} >> ^V146 ^V13 ^V146 ^V107

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

0 S ^V146 ^V167

Як це буде виглядати так на екрані (in 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ці жетони. Можливо, мені потрібен режим, який я повинен увімкнути. ]


Можливо, це щось стосується цієї програми. Онлайн Ущільнювач не подобається, коли.
luser droog

1

Змініть негативні рулони на позитивні

Негативні рулони завжди можуть бути змінені на позитивні .

3 -1 roll
3 2 roll

5 -2 roll
5 3 roll

Що є більш ефективним 3 -1 rollабо 3 2 roll? У моїй ментальній моделі колишня повинна бути ефективнішою, оскільки вона займає лише один крок. Чи правильна моя ментальна модель?
поцілуй мою пахву

Чесно кажучи, я не впевнений. Ось моя реалізація , де всі негативні рулони перетворюються на позитивні як перший крок. Я думаю, що все-таки знадобиться принаймні 2 ходи (перемістити 3-е значення вгору , перемістити 3 значення вниз ) з реалізацією стека з плоским масивом. Але мій стек сегментований, тому доступ проходить через виклики функцій для управління сегментами; тож, безумовно, є більш ефективні способи реалізації, ніж я. ... Одне, що я бачу зараз: я повинен перевірити, чи є стічний потік поза петлями.
luser droog

1
Вихідний файл перемістився з мого останнього коментаря. Ось моя реалізація на rollоператора.
luser droog

0

Використовувати мою G-бібліотеку

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

Це текстовий файл. Немає розширення для найкоротшого можливого синтаксису для завантаження.

Це дозволяє цю 203-програмову програму Sierpinksi Triangle

[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 для 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.