Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 14, 2021 07:17 pm GMT

100 Languages Speedrun: Episode 24: Postscript

Postscript was sort of predecessor to PDF, but unlike PDF, Postscript just includes a full stack-based programming language.
It wasn't really meant for humans to write code in, just for various typesetting systems to generate, but that's not going to stop us - let's code some things!

To "run" the programs we'll just view them with OSX Preview.

Hello, World!

%!PS/Monaco 32 selectfont200 400 moveto(Hello, World!) showshowpage

It's obvious what we're starting with.

Here's the result:

Hello

What's going on here:

  • %!PS is the Postscript header
  • we have stack-based programming language, like Forth we've seen before
  • /Monaco 32 selectfont pushes two values on stack, then selects Monaco 32pt font
  • 200 400 moveto pushes two number on stack, then moves cursor there - in Postscript (0,0) is bottom left, not top left like with usual computer graphics
  • (Hello, World!) show pushes string on stack, then shows it
  • showpage shows the page we just drew
  • also notice the header saying hello.pdf not hello.ps - OSX Preview converts Postscript files to PDF before displaying them

That wasn't too bad.

Loops

The first step towards real programming would be doing a loop:

%!PS/Monaco 32 selectfont0 1 10 {                % STACK CONTENTS:                % i  dup 30 mul    % i 30i  600 exch sub  % i 600-30i  300           % i 600-30i 300  exch          % i 300 600-30i  moveto        % i  20 string cvs % "i" (as string of max size 20 chars)  show} forshowpage

Which looks like this:

Loop

I annotated in % comments what's stack contents after each iteration. Let's go over it step by step:

  • 0 1 10 { ... } for is a lop from 0 to 10, step size 1
  • dup 30 mul duplicates index and multiplies it by 30
  • 600 exch sub does 600-30i - we need to exchange top two values on the stack with exch, otherwise we'd have 30i-600. As I mentioned, Postscript Y coordinates are upside down compared with the usual convention.
  • 300 exch pushes 300, and then exchanges top two values on the stack, then we moveto that position
  • 20 string cvs converts integer to string - or technically speaking allocates string of 20 empty characters, then outputs i there
  • show puts that string on the page

Double numbers

For next step let's define a custom function to double numbers, and do a bit of formatting.

%!PS/Helvetica 32 selectfont/double {  dup add} def1 1 10 {  dup 30 mul  600 exch sub  100  exch  moveto  (double\() show  dup 20 string cvs show  (\) = ) show  double 20 string cvs show} forshowpage

Which looks like this:

Double

Step by step:

  • /double { ... } def defines a function double that takes one number and doubles it - as it's a stack-based language there are no specific "arguments" and "return values", function just doubles whatever is on top of the stack
  • (double\() show shows some escaping of special characters like ( and ) in strings.
  • when we show something, cursor moves to the end of shown string, os we don't need to reposition each thing we print if it's on the same line
  • we call the function double the same way as we call any builtin functions

Fibonacci

Now we have almost everything we need to do Fibonacci numbers.

%!PS/Helvetica 20 selectfont/fib {  dup 2 le {    pop    1  } {    dup 1 sub fib    exch    2 sub fib    add  } ifelse} def1 1 30 {  dup 20 mul  700 exch sub  50  exch  moveto  (fib\() show  dup 20 string cvs show  (\) = ) show  fib 20 string cvs show} forshowpage

Which looks like this:

Fib

Step by step:

  • the loop is just as before
  • fib function contains big condition { then branch } { else branch } ifelse statement - code blocks in {} are passed to ifelse just like they are passed to def and only executed when needed
  • dup 2 le is top-of-stack <= 2
  • in then-branch pop 1 removes top item from stack (we only need it in the else branch), and pushes 1 instead as return value
  • in else-branch, we first dup 1 sub fib to call fib(n-1)
  • then we exch to swap calculated fib(n-1) with n
  • then we do 2 sub fib to calculate fib(n-2)
  • and finally we add those two values together

FizzBuzz

Let's do FizzBuzz, obviously. But we have a small problem - 1 to 100 FizzBuzz won't fit on one page. Well, how about we do two pages then?

%!PS/Helvetica 14 selectfont/fizzbuzz {  dup 15 mod 0 eq {    pop (FizzBuzz)  } {    dup 5 mod 0 eq {      pop (Buzz)    } {      dup 3 mod 0 eq {        pop (Fizz)      } {        20 string cvs      } ifelse    } ifelse  } ifelse} def/fizzbuzzpage {  /n exch def  1 1 50 {    dup 14 mul    780 exch sub    50    exch    moveto    n add fizzbuzz show  } for  showpage} def0 fizzbuzzpage50 fizzbuzzpage

Which looks like this, with each page for 50 values:

Fizzbuzz

Step by step:

  • fizzbuzz taken a number and returns Fizz, Buzz, FizzBuzz, or string representation of that number, according to the usual FizzBuzz rules
  • fizzbuzzpage takes an offset and prints a page full of FizzBuzz values, from N+1 to N+50
  • /n exch def saves top of the stack to n variable - Postscript can access values deep in the stack, but I think it's easier to just save it as a local variable. We need the exch as expected order is /name value def, and we already have value on top before we even start. You can use this technique to save any number of function call arguments into local variables, starting from the last one.
  • n add fizzbuzz show calculates fizzbuzz(n+i) and shows it on the page

Should you use Postscript?

Definitely not for programming, and nowadays not even for typesetting as PDFs pretty much replaced Postscript completely, but it's a decent enough introduction to stack-based languages, probably more fun than Forth as you can do fancy graphics in Postscript.

Depending on your printer, you could even send your program directly to the printer, to run it onto the page, without ever running it on any regular computer.

Code

All code examples for the series will be in this repository.

Code for the Postscript episode is available here.


Original Link: https://dev.to/taw/100-languages-speedrun-episode-24-postscript-4i2k

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To