Tell me more ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

As one of the less popular languages, it's difficult to find literature on the avant garde of postscript hackery. So what discoveries have the golfers here made to exploit the stack model (or other features) to overcome Postscript's inherent verbosity?

Please, one tip per answer.

share|improve this question
Made CW in keeping with our tips policy. – dmckee Oct 27 '12 at 0:00
Understood. willco. – luser droog Oct 27 '12 at 0:09
Found some external pages: sites.google.com/site/codegolfingtips/Postscript – luser droog Nov 20 '12 at 6:14

6 Answers

While most postscript operators are syntactically identifiers (and therefore must be space- (or otherwise-) delimited), the names [, ], <<, and >> are self-delimiting and scanner will detect them without intervening space. For the same reason, you cannot refer to these names with the usual /literal syntax (eg. /[ is two tokens: an empty literal name equivalent to ()cvn cvlit, and the executable name [ equivalent to ([)cvn cvx exec).

This example illustrates abusing these operators to perform arithmetic.

%!
([)0 def
(])1 def
(<<){add}def
(>>){mul}def
 ]]<<]]]<<<<>> =
%1 1 add 1 1 1 add add mul = %prints 6
share|improve this answer
2  
Also, / ends the previous token so you don't need a space before it. – Geoff Reedy Oct 27 '12 at 2:32

Here's a quickie: wrap multiple definitions in <<...>>begin to eliminate the keyword def.

defdefdef
<<>>begin

So remember: more than three ... flock together! ;)

share|improve this answer

Replace hexstrings with ASCII85

Probably old news, but I just learned it. :)

You can do it using the postscript interpreter interactively with an encoding filter and cut-and-paste. But I'm going to show how to use dc to do it "by hand".

So, here's a hex string. We split it into 4-byte chunks.

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

Firing up dc, we input these as 32-bit (unsigned) numbers. Then mod-off base-85 digits (there should be 5 until you get to 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 the last chunk with 00 00, yields (decimal), omitting the same number of bytes that we padded.

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

Add 33 to shift into the printable range of ASCII and poof! ASCII85.

80 111 115 116 115 99 114 105 112 116 58 105 115 58 102 35 86 63
Postscript:is:f#V? %%%Oops! should say 'fun'! I screwed up somewhere. :)

Wrap it in <~ ... ~>, and Level-2 Postscript can access 8-bit data, cheaper than hex.

share|improve this answer

When generating graphical output and console output does not matter, use = instead of pop.

share|improve this answer

Embedded Decoder

A Postscript program has a unique(?) ability to read it's own program text as data. This is normally used by the image operator which receives a data-acquisition-procedure as input, and this procedure often uses currentfile followed by readline, readstring, or readhexstring. But seen another way, image is just another looping operator, so any loop can read-ahead. An example is the line-printer emulator from the Green Book.

Using the token operator invokes the scanner on a file or string, pulling off a number or space- (or otherwise-: see other answer) -delimited name.

A simple PS interpreter in PS:

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

[I've only scratched the surface of this subtopic, please add more!]

share|improve this answer

Factor-out repeated uses of long operator names

If you're already using a <<>>begin dictionary, there is a constant overhead of /?{} 4 characters per redefinition. So an operator of length n repeated N times will yield a character-count change of
(4 + n) - (N * (n - 1)).

Setting this formula equal to 0 gives the equation of the break-even point. From this we can solve for each variable in terms of the other, yielding
n = - (N - 4) / (1 - N) and
N = (4 + n) / (n - 1) .

No we can answer questions like, "For how many uses of 'print' is it worthwhile to abbreviate?" n = 5, so N = 9/4. Take the ceiling, since you can't effectively call print 1/4 times. So, 3. 3 uses. And indeed,

print print print
/P{print}p p p

(assuming you've already paid the overhead of <<>>begin to activate the definition, of course).

Of course, binary tokens makes this kind of moot, giving you the first 255 names from the system name table as 2-bytes: 0x92, 0x??. And binary tokens are also self-delimiting, requiring no whitespace before or after, since the high-bit of the first byte is outside of the ascii range.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.