Kiat bermain golf di Postscript?

14

Sebagai salah satu bahasa yang kurang populer, sulit untuk menemukan literatur tentang avant garde dari peretasan postscript. Jadi, penemuan apa yang dilakukan pegolf di sini untuk mengeksploitasi model tumpukan (atau fitur lainnya) untuk mengatasi verbositas inheren Postscript?

luser droog
sumber
Menemukan beberapa halaman eksternal: sites.google.com/site/codegolfingtips/Postscript
luser droog

Jawaban:

3

Decoder Tertanam

Program Postscript memiliki kemampuan unik (?) Untuk membaca teks program itu sendiri sebagai data. Hal ini biasanya digunakan oleh imageoperator yang yang menerima data akuisisi-prosedur sebagai masukan, dan prosedur ini sering menggunakan currentfilediikuti oleh readline, readstringatau readhexstring. Tapi melihat cara lain, imagehanyalah operator pengulangan, sehingga setiap pengulangan dapat membaca-depan . Contohnya adalah emulator line-printer dari Green Book.

Menggunakan tokenoperator memanggil pemindai pada file atau string, menarik nomor atau spasi- (atau sebaliknya-: lihat jawaban lain) -nama awal.

Penerjemah PS sederhana dalam PS:

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

Decoder Operator Biner

Karena saya sepertinya tidak bisa mendapatkan token biner mentah untuk bekerja untuk saya (lihat jawaban lain), saya telah menggunakan ide "decoding tertanam" untuk mengeksploitasi mekanisme token biner untuk mengemas kode menjadi string 8-bit, dan kemudian memanipulasi dan mengurai perintah dari string dengan cepat .

/.{
    <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

The .Prosedur mengambil nomor dari stack dan sisipan sebagai byte kedua dalam serangkaian dua-byte, byte pertama menjadi awalan-byte untuk token biner, menentukan nama sistem executable. Kami menyimpan byte dalam hexstring dengan menggunakan aturan pemindai bahwa jumlah aneh gigitan dalam hexstring diisi dengan 0 gigitan tambahan, sehingga 3 hex gigitan menghasilkan string 2-byte. String kemudian ditandai dapat dieksekusi dan dipanggil dengan execyang memanggil pemindai, menghasilkan nama sistem yang dapat dieksekusi yang diinginkan, dan kemudian memuat nama dan mengeksekusi operator. The $melakukan ini pada setiap byte dari string di stack, dengan menggunakan .prosedur dua kali , sekali sebagai tubuh loop, dan kemudian mengeksekusi operator perulangan foralldengan nomor.

Lebih ringkasnya, prosedur ini terlihat seperti ini:

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

Jadi, 55 karakter membeli string token biner. Atau, untuk 6 (mungkin 7, jika Anda mengakhirinya dengan spasi) karakter, Anda dapat memuat perpustakaan G dengan(G)run yang mendefinisikan .dan $seperti di atas (+ beberapa orang lain untuk memperluas jangkauan dari kode ascii-terjangkau).

Lebih lanjut diilustrasikan dalam jawaban teka-teki silang saya .

luser droog
sumber
1
Sebenarnya, jika nota bene dalam bentuk kode, maka ini mengharuskan Anda ekstra hati-hati membandingkan barang. Secara khusus, jika Anda mencari di operator, Anda harus mengurai sebagai tanda dan kemudian membandingkan token nama ke nilai target.
AJMansfield
2

Saat menghasilkan output grafis dan output konsol tidak masalah, gunakan =sebagai gantinya pop.

Thomas W.
sumber
2

Ganti hexstrings dengan ASCII85

Mungkin berita lama, tapi saya baru mempelajarinya. :)

Anda dapat melakukannya menggunakan juru bahasa postscript secara interaktif dengan filter penyandian dan cut-and-paste. Tapi saya akan menunjukkan cara menggunakannyadc untuk melakukannya "dengan tangan".

Jadi, inilah string hex. Kami membaginya menjadi potongan 4-byte.

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

Mengaktifkan dc, kami memasukannya sebagai nomor pesanan big-endian-byte-32-bit (tidak ditandatangani). Kemudian mod -off base-85 digit (harus ada 5 sampai Anda mendapatkan 0).

0> dc
16i
95206ED8
Ai
d85% n85 /
82
d85% n85 /
83
d85% n85 /
82
d85% n85 /
78
d85% n85 /
47
d85% n85 /
0                    

Padding potongan terakhir dengan 00 00, menghasilkan (desimal), menghilangkan jumlah byte yang sama dengan yang kita empuk.

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

Tambahkan 33 untuk beralih ke kisaran ASCII dan poof yang dapat dicetak! ASCII85.

80 111 115 116 115 99 114 105 112 116 58 105 115 58 102 35 86 63
yang diterjemahkan ke: Postscript: is: f # V? %%% Ups! harus mengatakan 'menyenangkan'! Saya mengacau di suatu tempat. :)

Bungkus <~... ~>, dan Postscript Level-2 dapat mengakses data 8-bit, lebih murah daripada hex.

luser droog
sumber
2

Ini quickie: masukkan beberapa definisi [...>>beginuntuk menghilangkan kata kunci def(nb. [Sama dengan <<).

 def def
[>>begin

Jadi ingat: lebih daritigadua ... berkumpul bersama ! ;)

luser droog
sumber
Bukankah seharusnya aturannya "lebih dari dua"? Bandingkan /a 1 def/b 2 def/c 3 defdengan <</a 1/b 2/c 3>>begin. Kami membutuhkan lebih banyak ruang untuk def.
Thomas W.
Wow. Saya belum memikirkan hal itu. Ya, perhitungannya perlu ditingkatkan.
luser droog
Sebenarnya, ini seharusnya[/a 1/b 2/c 3>>begin
Thomas W.
Telapak tangan. . . .
luser droog
1
Ini mungkin tidak berlaku jika Anda memberi nama sesuatu yang berakhir pada token yang membatasi sendiri. Dalam /a{pop 2 mul}defatau \b[2 3]def, defsatu - satunya biaya 3 karakter, bukan 4.
AJMansfield
2

Sementara sebagian besar operator postscript sintaksis pengidentifikasi (dan karena itu harus ruang-(atau otherwise-) delimited), nama-nama [, ], <<, dan >>yang self-pembatasan dan scanner akan mendeteksi mereka tanpa intervensi ruang. Untuk alasan yang sama, Anda tidak dapat merujuk nama-nama ini dengan /literalsintaksis yang biasa (mis. /[Adalah dua token: nama literal kosong yang setara dengan ()cvn cvlit, dan nama yang dapat dieksekusi [setara dengan ([)cvn cvx exec).

Untuk mendefinisikan kembali nama-nama ini, yang tidak dapat disebutkan namanya, kita dapat menggunakan string yang secara implisit dikonversi menjadi nama saat digunakan sebagai kunci dalam kamus (nyaman!).

Contoh ini menggambarkan penyalahgunaan operator ini untuk melakukan aritmatika.

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

Juga <<dan [(dan mark) semua memiliki arti yang sama.


Penerjemah postscript saya sendiri, xpost , juga membuat kurung kurawal yang tepat tersedia dengan beberapa batasan. diskusi

luser droog
sumber
2
Juga, /akhiri token sebelumnya sehingga Anda tidak perlu spasi sebelum itu.
Geoff Reedy
1

Pemakaian faktor-faktor berulang dari operator yang panjang

Jika Anda sudah menggunakan <<>>beginkamus, ada overhead konstan /?{}4 karakter per redefinisi. Jadi operator dengan panjang n yang diulang N kali akan menghasilkan perubahan karakter-hitung
(4 + n ) - ( N * ( n - 1)).

Menyetel rumus ini sama dengan 0 memberikan persamaan titik impas . Dari sini kita dapat menyelesaikan untuk setiap variabel dalam hal yang lain, menghasilkan
n = - ( N - 4) / (1 - N ) dan
N = (4 + n ) / ( n - 1).

Tidak, kami dapat menjawab pertanyaan seperti, "Untuk berapa banyak penggunaan 'cetak' yang layak disingkat?" n = 5, jadi N = 9/4. Ambillah plafon, karena Anda tidak dapat secara efektif memanggil cetak 1/4 kali. Jadi, 3. 3 menggunakan. Dan memang,

print print print
/P{print}p p p

(dengan asumsi Anda sudah membayar overhead <<>>beginuntuk mengaktifkan definisi, tentu saja).

Tentu saja, token biner membuat jenis ini dapat diperdebatkan, memberi Anda 255 nama pertama dari tabel nama sistem sebagai 2-byte: 0x92, 0x ??. Dan token biner juga membatasi sendiri, tidak memerlukan spasi putih sebelum atau sesudah, karena bit tinggi dari byte pertama berada di luar rentang ascii.

luser droog
sumber
1

Token Biner

Untuk yang terakhir zip-up akhir dari program PostScript yang perbatasan akhir adalah token biner yang memungkinkan Anda untuk menghapus nama operator yang panjang sepenuhnya, dengan biaya tidak lagi memiliki program ASCII-clean.

Jadi dimulai dengan blok kode postscript yang dipadatkan

[/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

Kami mencari semua nama di belakang PLRM (Lampiran F, hal. 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

Dan kemudian ketik di awalan oleh 146 byte (desimal). bantuan vim untuk memasukkan byte acak

Kemudian dalam vim, file yang diringkas dapat diketik langsung, jadi:

[/ T [70 {R 0 ^V146 ^V133} 48 {} 49 {} 43 {A ^V146 ^V136} 45 {A ^V146 ^V110^V 146 ^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 62^V57} { ^V146 ^V62 { ^V146 ^V100 ^V146^V

... Anda harus memasukkan spasi di sini untuk mengakhiri ^V -62 dan memulai 1, tetapi Anda dapat mencadangkan dan menghapusnya nanti ...

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

... harus memasukkan spasi di sini untuk mengakhiri ^V -85 dan memulai 1, tetapi Anda dapat mencadangkan dan menghapusnya nanti ...

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

... Digit ke-3 dari kode 3 digit mengakhiri byte-entry jadi berikut ini 0 ini normal, dengan mudah ...

0 S ^V146^V 167

Yang akan terlihat seperti ini di layar (dalam 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>§

Yang ini sering dapat dihilangkan seluruhnya jika tujuannya hanya untuk menunjukkan gambar. Ghostscript melukis sebagian besar hal ke layar tanpa perlu showpage.

¡    161   showpage

[ Ini sebenarnya tidak berhasil. Ghostscript memberi saya undefineddan syntaxerroruntuk token ini. Mungkin ada beberapa mode yang perlu saya aktifkan. ]

luser droog
sumber
Mungkin ada sesuatu tentang program ini . The pemadat secara online tidak seperti itu, baik.
luser droog
1

Ubah gulungan negatif menjadi positif

Gulungan negatif selalu dapat diubah menjadi gulungan positif .

3 -1 roll
3 2 roll

5 -2 roll
5 3 roll
luser droog
sumber
Mana yang lebih efisien 3 -1 rollatau 3 2 roll? Dalam model mental saya, yang pertama harus lebih efisien karena hanya perlu satu langkah. Apakah model mental saya benar?
Cium ketiakku
Jujur, saya tidak yakin. Inilah implementasi saya , di mana semua gulungan negatif dikonversi menjadi positif sebagai langkah pertama. Saya pikir masih akan membutuhkan setidaknya 2 bergerak (pindah nilai 3 sampai , bergerak 3 nilai-nilai ke bawah ) dengan implementasi datar array stack. Tapi tumpukan saya tersegmentasi sehingga akses melewati panggilan fungsi untuk mengelola segmen; jadi pasti ada cara yang lebih efisien untuk diterapkan daripada yang telah saya lakukan. ... Satu hal yang saya lihat sekarang: Saya harus memeriksa stackunderflow di luar loop.
luser droog
1
File sumber telah dipindahkan sejak komentar terakhir saya. Berikut implementasi saya dari rolloperator.
luser droog
0

Gunakan perpustakaan G saya

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

Ini file teks. Tanpa ekstensi, untuk sintaks yang sesingkat mungkin untuk memuatnya.

Itu memungkinkan program 203-char Sierpinksi Triangle ini

[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

untuk ditulis ulang dalam 151 byte sebagai

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

workfile dengan komentar

Menggunakan fitur nama sistem yang disingkat, 1(G)run sepenuhnya menghilangkan beban nama operator yang panjang. Nama operator hanya perlu cukup panjang untuk membedakannya dari yang lain.

Begitu

  • add menjadi ad
  • mul menjadi mu
  • index menjadi i
  • dll, dll.

Menggunakan PLRM Apendiks F untuk tabel standar nama operator.

Dan fitur Operator Strings tersedia bahkan jika nama yang disingkat tidak dipilih. Pustaka kosong memiliki "level dasar" yang dipilih dengan menambahkan secara sederhana(G)run tanpa dekorasi lebih lanjut.

Level dasar mencakup fungsi baru . yang menerima kode integer untuk operator (Lampiran F yang sama yang disebutkan di atas) dan menjalankannya.

Fungsi baru ini $dijalankan melalui sebuah string dan panggilan. masing-masing. Jadi kode ascii langsung memilih operator dengan nomor.

Fungsi baru @ memungkinkan Anda menjangkau ke bawah tabel di Lampiran F dengan memperlakukan karakter spasi (Ascii 0x20) sebagai 0.

Fungsi baru #memungkinkan Anda menjangkau lebih jauh ke dalam tabel dengan terlebih dahulu menambahkan 95 (0x5F) sehingga spasi 0x20 diperlakukan sebagai 127 (0x7F), kode berikutnya setelah karakter ascii terakhir yang dapat dicetak.~ 126 (0x7E).

Dua fungsi baru !memungkinkan Anda mengakses struktur array dan / atau dict yang bersarang dengan array indeks indeks / kunci, daripada ekspresi yang membosankan dari banyak get(dan put) operator.

(G)run 7 karakter membeli level dasar.

1(G)run 8 karakter membeli dan nama sistem disingkat.

3(G)run $9 karakter segera memulai prosedur implisit blok sumber pemindaian baris sampai baris kosong berikutnya, dan mendefinisikan baris pertama sebagai prosedur yang disebut A, baris berikutnya didefinisikan sebagai prosedur yang disebut B, dll. Ini harus menghapus sebagian besar yang defdiperlukan untuk mendefinisikan banyak hal, tanpa perlu membungkusnya dalam kamus, atau bahkan secara eksplisit memberi mereka nama.

luser droog
sumber