Como uno de los idiomas menos populares, es difícil encontrar literatura sobre la vanguardia de la piratería de postscript. Entonces, ¿qué descubrimientos han hecho los golfistas aquí para explotar el modelo de pila (u otras características) para superar la verbosidad inherente de Postscript?
14
Respuestas:
Decodificador Integrado
Un programa Postscript tiene una capacidad única (?) Para leer su propio texto de programa como datos. Esto se usa normalmente por el
image
operador que recibe una adquisición-procedimiento de datos como entrada, y este procedimiento utiliza a menudocurrentfile
seguido porreadline
,readstring
oreadhexstring
. Pero visto de otra manera,image
es solo otro operador de bucle, por lo que cualquier bucle puede seguir leyendo . Un ejemplo es el emulador de impresora de líneas del Libro Verde.El uso del
token
operador invoca el escáner en un archivo o cadena, extrayendo un número o espacio (o de lo contrario: ver otra respuesta) nombre delimitado.Un simple intérprete de PS en PS:
Decodificador de cadena de operador binario
Ya que parece que no puede obtener primas símbolos binarios a trabajar para mí (ver otra respuesta), he hecho uso de la "incrustados decodificar" la idea de explotar el mecanismo símbolo binario para empacar código en cadenas de 8 bits, y luego manipular y analizar los comandos de la cadena sobre la marcha .
El
.
procedimiento toma un número de la pila y lo inserta como el segundo byte en una cadena de dos bytes, siendo el primer byte el prefijo-byte para un token binario, especificando un nombre de sistema ejecutable. Guardamos un byte en la cadena hexagonal mediante el uso de una regla del escáner de que un número impar de mordiscos en la cadena hexagonal se rellena con un mordisco 0 adicional, por lo que 3 mordiscos hexagonales producen una cadena de 2 bytes. La cadena se marca como ejecutable y se llama con loexec
que invoca el escáner, produce el nombre del sistema ejecutable deseado, y luego carga el nombre y ejecuta el operador. El$
hace esto en cada byte de una cadena en la pila, usando el.
procedimiento dos veces , una vez como el cuerpo del bucle, y luego para ejecutar el operador de bucleforall
por número.De manera más compacta, estos procedimientos se ven así:
Entonces, 55 caracteres compra cadenas de fichas binarias. O, para los caracteres 6 (quizás 7, si lo termina con un espacio), puede cargar la biblioteca G con la
(G)run
que se define.
y$
como arriba (+ algunos otros para ampliar el rango de códigos ascii-alcanzables).Más ilustrado en mi crucigrama respuesta .
fuente
Cuando la salida gráfica y la salida de la consola no importen, use en
=
lugar depop
.fuente
Reemplace las cadenas hexagonales con ASCII85
Probablemente viejas noticias, pero acabo de enterarme. :)
Puede hacerlo utilizando el intérprete PostScript de forma interactiva con un filtro de codificación y cortar y pegar. Pero voy a mostrar cómo usarlo
dc
"a mano".Entonces, aquí hay una cadena hexadecimal. Lo dividimos en trozos de 4 bytes.
Encendiendo dc, los ingresamos como números de orden de bytes grandes de 32 bits (sin signo). Luego mod -off base-85 dígitos (debe haber 5 hasta llegar a 0).
Rellenando el último fragmento con
00 00
, produce (decimal), omitiendo el mismo número de bytes que rellenamos.¡Agregue 33 para cambiar al rango imprimible de ASCII y poof! ASCII85.
Envuélvalo en
<~
...~>
, y Postscript de nivel 2 puede acceder a datos de 8 bits, más barato que el hexadecimal.fuente
Aquí hay un resumen: envuelva varias definiciones
[...>>begin
para eliminar la palabra clavedef
(nb.[
Es lo mismo que<<
).Así que recuerda: más que
Tresdos ... ¡ acuden juntos ! ;)fuente
/a 1 def/b 2 def/c 3 def
con<</a 1/b 2/c 3>>begin
. Necesitamos más espacios para def.[/a 1/b 2/c 3>>begin
/a{pop 2 mul}def
o\b[2 3]def
, eldef
único cuesta 3 caracteres, no 4.Aunque la mayoría de los operadores de PostScript son sintácticamente identificadores (y por lo tanto debe ser espacio-(u otros métodos) delimitada), los nombres
[
,]
,<<
, y>>
son auto-delimitación y escáner detectará sin espacio intermedio. Por la misma razón, no puede hacer referencia a estos nombres con la/literal
sintaxis habitual (por ejemplo,/[
son dos tokens: un nombre literal vacío equivalente a()cvn cvlit
, y el nombre ejecutable[
equivalente a([)cvn cvx exec
).Para redefinir estos nombres, que no se pueden mencionar por nombre, podemos usar cadenas que se convierten implícitamente en nombres cuando se usan como claves en un diccionario (¡conveniente!).
Este ejemplo ilustra el abuso de estos operadores para realizar operaciones aritméticas.
Además
<<
y[
(ymark
) todos significan lo mismo.Mi propio intérprete de postscript, xpost , también hace que la llave derecha esté disponible con algunas restricciones. discusión
fuente
/
finaliza el token anterior para que no necesite un espacio antes.Factorizar usos repetidos de nombres de operador largos
Si ya está utilizando un
<<>>begin
diccionario, hay una sobrecarga constante de/?{}
4 caracteres por redefinición. Por lo tanto, un operador de longitud n repetido N veces producirá un cambio de recuento de caracteres de(4 + n ) - ( N * ( n - 1)).
Establecer esta fórmula igual a 0 da la ecuación del punto de equilibrio . De esto podemos resolver para cada variable en términos de la otra, produciendo
n = - ( N - 4) / (1 - N ) y
N = (4 + n ) / ( n - 1).
No, podemos responder preguntas como: "¿Para cuántos usos de 'imprimir' vale la pena abreviar?" n = 5, entonces N = 9/4. Tome el techo, ya que no puede llamar efectivamente a imprimir 1/4 veces. Entonces, 3. 3 usos. Y de hecho,
(suponiendo que ya ha pagado los gastos generales
<<>>begin
para activar la definición, por supuesto).Por supuesto, los tokens binarios hacen que este tipo de discusión sea discutible, dándote los primeros 255 nombres de la tabla de nombres del sistema como 2 bytes: 0x92, 0x ??. Y los tokens binarios también se auto delimitan, no requieren espacios en blanco antes o después, ya que el bit alto del primer byte está fuera del rango de ascii.
fuente
Fichas Binarias
Para el último zip-up de un programa PostScript, esa frontera final son tokens binarios que le permiten eliminar completamente nombres largos de operadores, a costa de no tener un programa ASCII-clean.
Comenzando con un bloque compactado de código postscript
Buscamos todos los nombres en la parte posterior del PLRM (Apéndice F, pp. 795-797)
Y luego escríbalos con el prefijo un
146
byte (decimal). vim ayuda para ingresar bytes arbitrariosLuego, en vim, el archivo condensado se puede escribir directamente, por lo que:
... debe ingresar un espacio aquí para terminar el
^V
-62 e iniciar el 1, pero puede hacer una copia de seguridad y eliminarlo más tarde ...... tiene que ingresar un espacio aquí para terminar el
^V
-85 e iniciar el 1, pero puede hacer una copia de seguridad y eliminarlo más tarde ...... el tercer dígito del código de 3 dígitos termina la entrada de bytes, por lo que lo siguiente
0
aquí es normal, convenientemente ...Que se verá así en la pantalla (en vim):
Este a menudo se puede omitir por completo si el objetivo es solo mostrar una imagen. Ghostscript pinta la mayoría de las cosas en la pantalla sin necesidad
showpage
.[ Esto en realidad no está funcionando. Ghostscript me está dando
undefined
ysyntaxerror
por estas fichas. Tal vez hay algún modo que necesito habilitar. ]fuente
Cambiar rollos negativos a positivos
Los rollos negativos siempre se pueden cambiar a rollos positivos .
fuente
3 -1 roll
o3 2 roll
? En mi modelo mental, el primero debería ser más eficiente porque solo toma un movimiento. ¿Es correcto mi modelo mental?roll
operador.Usa mi biblioteca G
https://github.com/luser-dr00g/G
Es un archivo de texto. Sin extensión, para la sintaxis más corta posible para cargarlo.
Permite este programa Sierpinksi Triangle de 203 caracteres
para ser reescrito en 151 bytes como
archivo de trabajo con comentarios
El uso de la función abreviada de nombres de sistema
1(G)run
elimina por completo la carga de los nombres largos de operadores. El nombre de un operador solo debe ser lo suficientemente largo como para distinguirlo de los demás.Entonces
add
se conviertead
mul
se conviertemu
index
se conviertei
Use el Apéndice F de PLRM para la tabla estándar de nombres de operadores.
Y la función de Operator Strings está disponible incluso si los nombres abreviados no están seleccionados. La biblioteca básica tiene un "nivel base" seleccionado al agregar simplemente
(G)run
sin más decoraciones.El nivel base incluye una nueva función
.
que acepta el código entero para un operador (el mismo Apéndice F mencionado anteriormente) y lo ejecuta.La nueva función
$
itera a través de una cadena y llama.
a cada una. Entonces, el código ASCII selecciona directamente al operador por número.Una nueva función le
@
permite llegar al final de la tabla en el Apéndice F al tratar el carácter de espacio (Ascii 0x20) como 0.Una nueva función le
#
permite llegar más arriba en la tabla agregando primero 95 (0x5F) para que el espacio char 0x20 se trate como 127 (0x7F), el siguiente código después del último carácter ascii imprimible~
126 (0x7E).Dos nuevas funciones le
!
permiten acceder a una estructura profundamente anidada de matrices y / o dictados con una matriz de índices / claves, en lugar de expresiones tediosas de muchosget
(yput
) operadores.(G)run
7 caracteres compra el nivel base.1(G)run
8 caracteres compra eso y abrevia los nombres del sistema.3(G)run $
9 caracteres comienza inmediatamente un bloque de procedimiento implícito explorando líneas de origen hasta la siguiente línea en blanco, y definiendo la primera línea como un procedimiento llamadoA
, la siguiente línea se define como un procedimiento llamadoB
, etc. Esto debería eliminar la mayoría de losdef
s necesarios para definir muchas cosas, sin necesidad de envolverlas en un diccionario, ni siquiera darles nombres explícitamente.fuente