Als eine der weniger populären Sprachen ist es schwierig, Literatur über die Avantgarde des Postscript-Hackery zu finden. Welche Entdeckungen haben die Golfer hier gemacht, um das Stack-Modell (oder andere Merkmale) zu nutzen, um die inhärente Ausführlichkeit von Postscript zu überwinden?
14
Antworten:
Embedded Decoder
Ein Postscript-Programm hat die einzigartige Fähigkeit, seinen eigenen Programmtext als Daten zu lesen. Dies wird normalerweise durch den verwendeten
image
Operator empfängt , die einen Datenerfassungsprozedur als Eingabe, und dieses Verfahren häufig verwendet ,currentfile
gefolgt vonreadline
,readstring
, oderreadhexstring
. Aber eine andere Art und Weise zu sehen ist ,image
ist nur ein weiterer Looping - Operator, so dass jede Schleife kann Read-Ahead . Ein Beispiel ist der Zeilendrucker-Emulator aus dem Green Book.Wenn Sie den
token
Operator verwenden, wird der Scanner für eine Datei oder eine Zeichenfolge aufgerufen, wobei ein durch eine Zahl oder ein Leerzeichen (oder etwas anderes) begrenzter Name abgerufen wird.Ein einfacher PS-Interpreter in PS:
Binäroperator-String-Decoder
Da ich scheinbar keine rohen Binärtoken für mich zum Laufen bringen kann (siehe andere Antwort), habe ich die Idee der "eingebetteten Dekodierung" genutzt, um den Binärtoken-Mechanismus auszunutzen, um Code in 8-Bit-Zeichenfolgen zu packen, und dann Manipulieren und analysieren Sie die Befehle aus der Zeichenfolge im laufenden Betrieb .
Die
.
Prozedur entnimmt eine Zahl aus dem Stapel und fügt sie als zweites Byte in eine Zwei-Byte-Zeichenfolge ein, wobei das erste Byte das Präfix-Byte für ein binäres Token ist und einen ausführbaren Systemnamen angibt. Wir speichern ein Byte im Hexstring, indem wir die Regel des Scanners verwenden, dass eine ungerade Anzahl von Halbbytes im Hexstring mit einem zusätzlichen 0-Halbbyte aufgefüllt wird, sodass 3 Hex-Halbbytes einen 2-Byte-String ergeben. Die Zeichenfolge wird dann als ausführbar markiert und aufgerufen,exec
wodurch der Scanner aufgerufen wird, der gewünschte Name des ausführbaren Systems erzeugt wird, der Name geladen und der Operator ausgeführt wird. Das$
tut dies für jedes Byte einer Zeichenfolge auf dem Stapel, mit der.
Prozedur zweimal , einmal als die Schleife und dann den Looping Bediener auszuführenforall
durch Nummer.Diese Prozeduren sehen kompakter wie folgt aus:
Also, 55 Zeichen kaufen binäre Token-Zeichenfolgen. Oder für 6 (vielleicht 7, wenn Sie es mit einem Leerzeichen abschließen) Zeichen können Sie die G-Bibliothek laden, mit
(G)run
der.
und$
wie oben definiert (+ einige andere, um den Bereich der über ASCII erreichbaren Codes zu erweitern).Weitere illustrierte in meinem Kreuzworträtsel Antwort .
quelle
Verwenden Sie
=
anstelle von, wenn Sie eine grafische Ausgabe erstellen und die Konsolenausgabe keine Rolle spieltpop
.quelle
Ersetzen Sie Hexstrings durch ASCII85
Wahrscheinlich alte Nachrichten, aber ich habe es gerade gelernt. :)
Sie können den Postscript-Interpreter interaktiv mit einem Codierungsfilter und Ausschneiden und Einfügen verwenden. Aber ich werde zeigen, wie
dc
man es "von Hand" macht.Also, hier ist eine Hex-Zeichenfolge. Wir haben es in 4-Byte-Blöcke aufgeteilt.
Beim Starten von DC geben wir diese als 32-Bit-Big-Endian-Byte-Ordnungszahlen (ohne Vorzeichen) ein. Dann mod -off base-85 Stellen (es sollte 5 geben, bis Sie auf 0 kommen).
Das Auffüllen des letzten Blocks mit
00 00
ergibt (dezimal), wobei die gleiche Anzahl von Bytes weggelassen wird, die wir aufgefüllt haben.Fügen Sie 33 hinzu, um in den druckbaren Bereich von ASCII und Poof zu wechseln! ASCII85.
Wrap it in
<~
...~>
und Level-2 Postscript kann auf 8-Bit-Daten zugreifen, die billiger als Hex sind.quelle
Hier ist eine kurze Beschreibung: Binden Sie mehrere Definitionen ein
[...>>begin
, um das Schlüsselwort zudef
entfernen (Nr. Ist[
dasselbe wie<<
).Also denk dran: mehr als
dreizwei ... scharen sich zusammen ! ;)quelle
/a 1 def/b 2 def/c 3 def
mit<</a 1/b 2/c 3>>begin
. Wir brauchen mehr Platz für def.[/a 1/b 2/c 3>>begin
/a{pop 2 mul}def
oder kostet\b[2 3]def
dasdef
nur 3 Zeichen, nicht 4.Während die meisten Postscript - Operatoren syntaktisch Identifikatoren sind (und damit platz- sein muss (oder otherwise-) begrenzt ist ), die Namen
[
,]
,<<
, und>>
sind selbstbegrenze und Scanner werden sie erkennen , ohne Raum dazwischen. Aus dem gleichen Grund, Sie nicht auf diese Namen mit der üblichen beziehen/literal
Syntax (. ZB/[
zwei Token: ein leerer wörtliche Namen entspricht()cvn cvlit
, und die Namen der ausführbaren Datei[
entspricht([)cvn cvx exec
).Um diese Namen neu zu definieren, die nicht namentlich erwähnt werden können, können wir Zeichenfolgen verwenden, die implizit in Namen konvertiert werden, wenn sie als Schlüssel in einem Wörterbuch verwendet werden (praktisch!).
In diesem Beispiel wird der Missbrauch dieser Operatoren zum Ausführen von Arithmetik veranschaulicht.
Auch
<<
und[
(undmark
) bedeuten alle dasselbe.Mein eigener Postscript-Interpreter, xpost , stellt mit einigen Einschränkungen auch die rechte geschweifte Klammer zur Verfügung. Diskussion
quelle
/
endet die bisherigen Token so dass Sie nicht einen Raum , bevor es brauchen.Vermeiden Sie wiederholte Verwendungen langer Bedienernamen
Wenn Sie bereits ein
<<>>begin
Wörterbuch verwenden, entsteht ein konstanter Overhead von/?{}
4 Zeichen pro Neudefinition. Ein Operator der Länge n, der N- mal wiederholt wird, ergibt eine Änderung der Zeichenanzahl von(4 + n ) - ( N * ( n - 1)).
Wenn Sie diese Formel auf 0 setzen, erhalten Sie die Gleichung für den Break-Even- Punkt. Daraus können wir für jede Variable im Hinblick auf die andere lösen und
n = - ( N - 4) / (1 - N ) und
N = (4 + n ) / ( n - 1) ergeben.
Nein, wir können Fragen beantworten wie: "Bei wie vielen Verwendungszwecken von 'Drucken' lohnt es sich, abzukürzen?" n = 5, also N = 9/4. Nehmen Sie die Decke, da Sie Print nicht 1/4 Mal aufrufen können. Also, 3. 3 verwendet. Und in der Tat,
(vorausgesetzt, Sie haben bereits den Aufwand für
<<>>begin
die Aktivierung der Definition bezahlt ).Natürlich machen binäre Token diese Art von Moot und geben Ihnen die ersten 255 Namen aus der Systemnamentabelle als 2-Bytes: 0x92, 0x ??. Binäre Token sind ebenfalls selbstbegrenzend und erfordern weder vorher noch nachher Leerzeichen, da das High-Bit des ersten Bytes außerhalb des ASCII-Bereichs liegt.
quelle
Binäre Token
Für das ultimative Zip-up eines PostScript-Programms besteht diese letzte Grenze aus binären Token, mit denen Sie lange Bedienernamen vollständig entfernen können, ohne ein ASCII-Clean-Programm mehr zu haben.
Beginnen Sie also mit einem komprimierten Block mit Postscript-Code
Wir schlagen alle Namen auf der Rückseite des PLRM nach (Anhang F, S. 795-797).
Und geben Sie sie dann mit einem
146
(Dezimal-) Byte voran ein. vim hilfe zur eingabe beliebiger bytesIn vim kann die komprimierte Datei dann direkt eingegeben werden.
... Sie müssen hier ein Leerzeichen eingeben, um die
^V
-62 zu beenden und die 1 zu starten, aber Sie können sie später sichern und löschen ...... müssen hier ein Leerzeichen eingeben, um die
^V
-85 zu beenden und die 1 zu starten, aber Sie können sie später sichern und löschen ...... Die dritte Ziffer des dreistelligen Codes beendet die Byte-Eingabe, so dass das Folgende
0
hier normal ist, bequemerweise ...Welches wird auf dem Bildschirm so aussehen (in vim):
Diese kann oft ganz weggelassen werden, wenn nur ein Bild gezeigt werden soll. Ghostscript malt die meisten Dinge auf den Bildschirm, ohne sie zu benötigen
showpage
.[ Das funktioniert eigentlich nicht. Ghostscript gibt mir
undefined
undsyntaxerror
für diese Token. Vielleicht gibt es einen Modus, den ich aktivieren muss. ]quelle
Ändern Sie die negativen Rollen in positive
Negative Rollen können immer in positive Rollen geändert werden .
quelle
3 -1 roll
oder3 2 roll
? In meinem mentalen Modell sollte das erstere effizienter sein, da es nur einen Schritt dauert. Ist mein mentales Modell korrekt?roll
Operators.Benutze meine G-Bibliothek
https://github.com/luser-dr00g/G
Es ist eine Textdatei. Keine Erweiterung, um die kürzest mögliche Syntax zu laden.
Es erlaubt dieses 203-Zeichen-Sierpinksi-Dreieck-Programm
umzuschreiben in 151 Bytes als
Arbeitsdatei mit Kommentaren
Durch die Verwendung der Funktion für abgekürzte Systemnamen
1(G)run
entfällt die Belastung durch lange Bedienernamen vollständig. Ein Bedienername muss nur lang genug sein, um ihn von den anderen zu unterscheiden.So
add
wirdad
mul
wirdmu
index
wirdi
Verwenden Sie den PLRM- Anhang F für die Standardtabelle der Bedienernamen.
Die Funktion von Operator Strings ist auch dann verfügbar, wenn die abgekürzten Namen nicht ausgewählt sind. Die nackte Bibliothek hat eine "Basisebene", die durch einfaches Hinzufügen
(G)run
ohne weitere Dekorationen ausgewählt wird.Die Basisebene enthält eine neue Funktion,
.
die den Integer-Code für einen Operator akzeptiert (derselbe oben erwähnte Anhang F) und ihn ausführt.Die neue Funktion
$
durchläuft eine Zeichenfolge und ruft.
jede auf. Der ASCII-Code wählt den Bediener also direkt nach seiner Nummer aus.Mit einer neuen Funktion
@
können Sie bis zum Ende der Tabelle in Anhang F vordringen, indem Sie das Leerzeichen (ASCII 0x20) als 0 behandeln.Mit einer neuen Funktion
#
können Sie weiter in die Tabelle vordringen, indem Sie zuerst 95 (0x5F) hinzufügen, sodass das Leerzeichen 0x20 als 127 (0x7F) behandelt wird, der nächste Code nach dem letzten druckbaren ASCII-Zeichen~
126 (0x7E).Mit zwei neuen Funktionen
!
können Sie auf eine tief verschachtelte Struktur von Arrays und / oder Dikten mit einem Indexarray von Indizes / Schlüsseln zugreifen , statt auf langwierige Ausdrücke vielerget
(undput
) Operatoren.(G)run
7 Zeichen kauft das Basislevel.1(G)run
8 Zeichen kaufen diese UND abgekürzten Systemnamen.3(G)run $
Mit 9 Zeichen beginnt eine implizite Prozedur sofort damit, die Quellzeilen bis zur nächsten leeren Zeile abzusuchen und die erste Zeile als aufgerufene ProzedurA
, die nächste Zeile als aufgerufene ProzedurB
usw. zu definieren . Dadurch sollten die meistendef
zum Definieren erforderlichen s entfernt werden viele Dinge, ohne sie in ein Wörterbuch einwickeln zu müssen oder ihnen sogar explizit Namen zu geben.quelle