Tahák na Postscript

PostScript je zásobníkový jazyk – program má implicitní zásobník přes který se předávají hodnoty. Příkaz typicky odebere ze zásobníku svůj vstup může tam zapsat nějaký výstup. Když napíšeme konstantu (například číslo 12, tak se přidá na zásobník). Příkazy a konstanty od sebe oddělujeme mezerami nebo novým řádkem, takže například 1 2 add přidá jedničku, dvojku a pak je sečte; na zásobníku tak zůstane trojka.

Proměnné a vlastní příkazy se definují příkazem def, který na vstupu očekává jméno a hodnotu. Například /pocet 5 def vyrobí proměnnou pocet. Prosté napsání pocet její hodnotu načte na zásobník, takže třeba pocet 1 add nechá na zásobníku pocet + 1. Když dáme část programu do složených závorek, vyrobíme tím spustitelný blok a když jej předáme příkazu def tak nám nadefinuje novou funkci. Například /plus1 { 1 add } def nám připraví příkaz na přičítání jedničky k hodnotě na vrcholu zásobníku.

Výstupem skriptu je vytištěný papír, v našem případě velikosti A4. Máme k dispozici celou řadu příkazů na kreslení, nejdůležitější pro nás bude kreslení čar. Lomená čára se začne pomocí příkazu newpath, pak můžeme volat X Y moveto pro přesunutí na souřadnice a X Y lineto na vykreslení čáry na souřadnice X Y. Příkaz stroke čáru vykreslí na stránku. Před jeho zavoláním si ještě můžeme vybrat barvu (r g b setrgbcolor) a tloušťku (t setlinewidth).

Může se hodit také zobrazovat text (například pro debugování). To dělá příkaz (Hello world!) show, font a velikost lze zvolit například takto /Courier 12 selectfont.

Obdobně bloky kódu použijeme pro podmínky a cykly - if, ifelse, repeat a for jsou jenom příkazy které nějak spouští bloky na zásobníku. Například 1 a eq { (a se rovna jedna) show } if vypíše daný text když a = 1. Obdobně funguje 1 a eq { (rovna se) show } { (nerovna se) show } ifelse.

Příkaz 10 { (X) show } repeat prostě vypíše 10krát X. Příkaz for je trochu sofistikovanější cyklus – iteruje přes proměnnou a bere hned 4 parametry – spodní hranici, velikost kroku a horní hranici.

Následující příklad vykreslí 11 rovnoběžných čar.

% iterujeme od 100 do 200 po deseti
100 10 200 {
    % tady máme na zásobníku iterační proměnnou
    newpath
    dup 100 moveto
        200 lineto
    stroke
} for

Občas se může hodit uložit hodnotu z vrchu zásobníku do proměnné. To můžeme udělat trikem využívajícím příkaz exch, který prohodí první dvě hodnoty na zásobníku. Můžeme pak psát například /promenna exch def. Trik je v tom, že zásobník bude postupně vypadat … X, … X /promenna a … /promenna X, a v posledním případě už můžeme zavolat def.

Praktický příklad

Níže následuje jednoduchý program kreslící domeček. Pozor, každý program v Postscriptu by měl začínat jednořádkovou hlavičkou %!PS, jinak ho tiskárna nemusí detekovat jako Postscriptový program. Na konci programu musí být příkaz showpage, který zobrazí vykreslenou stránku.

%!PS

/velikost 200 def % Velikost hrany
/pagewidth  currentpagedevice /PageSize get 0 get def % magic příkazy na zjištění rozměrů stránky
/pageheight currentpagedevice /PageSize get 1 get def

/rohx pagewidth velikost sub 2 div def % Spočítání levého rohu tak, aby byl domeček ve středu
/rohy pageheight velikost sub 2 div def

newpath
rohx rohy moveto
velikost 0 rlineto
0 velikost rlineto
velikost neg 0 rlineto
0 velikost neg rlineto
velikost velikost rlineto
rohx velikost add rohy moveto
velikost neg velikost rlineto
velikost 2 div dup rlineto
velikost 2 div dup neg rlineto
stroke
showpage

Užitečné příkazy

Práce se zásobníkem

Příkaz Vstup Výstup Popis
pop X Zahodí hodnotu
exch X Y Y X Vymění dvě hodnota
dup X X X Zduplikuje hodnotu
copy X1..Xn n X1..Xn X1..Xn Zduplikuje vrchních n hodnot
index Xn..X0 n Xn..X0 Xn Zkopíruje n-tý prvek navrch zásobníku
clear : X... : Smaže celý zásobník
count : X... : X... n Spočítá počet prvků na zásobníku

Aritmetika

Příkaz Vstup Výstup Popis
add x y x+y
div x y x/y
idiv x y x/y celočíselné dělení
mod x y x%y modulo
mul x y x*y
sub x y x-y
bitshift n i n' posune n o i bitů
abs x x
neg x -x
ceiling x ceil(x)
floor x floor(x)
round x round(x)
truncate x trunc(x)
sqrt x r
atan num den angle tan-1(num/den)
cos angle r všechny úhly jsou ve stupních
sin angle r
exp base exponent r
ln x r přirozený log
log x r desítkový log
rand - i
srand i - nastaví seed náhodného generátoru
rrand - i vrátí seed
ne, ge, gt, le, lt X Y b porovnávací operátory
and, not, or, xor b1 b2 b logické operátory
true - true
false - false

Cykly a podmínky

Příkaz Vstup Výstup Popis
exec X - spustí objekt na zásobníku
if f p - spustí p když f je true
ifelse f p1 p2 - spustí p1 když f je true nebo p2 když f je false
for x0 x++ x<= p - spustí p s hodnotami od x0 do x<= s kroky velikosti x++
repeat n p - spustí p n-krát
loop p - cyklí donekonečna
exit - - vyskočí z nejbližší smyčky

Konverze

Příkaz Vstup Výstup Popis
cvi n/s i konvertuje na int
cvn s name konvertuje na jméno
cvr n/s r konvertuje na reálné číslo
cvs X s s' konvertuje na string
cvrs n radix s s' konvertuje na string v dané soustavě

Před konverzí na string je potřeba předvyrobit string potřebné velikosti. Pokud máme (maximálně) tříciferné číslo, můžeme ho vypsat takto: mojeCislo 3 string cvs show. Když velikost čísla neznáme, můžeme prostě zvolit dostatečně vysokou konstantu a nebo si délku spočítat logartimem ;)

Pole

Příkaz Vstup Výstup Popis
array n a vyrobí pole délky n obsahující nully
[ - M začne konstruovat pole
] M X1..n a ukončí konstrukci pole - převede hodnoty na zásobníku na pole
length a n délka
get a i a[i] vrátí prvek i
put a i X - a[i]=X
getinterval a i n a[i..+n] vyřízne část pole jako nové pole
putinterval a i b - zapíše do pole jiné pole
aload a a[0]..a[n-1] a dá na zásobník všechny prvky pole
astore a[0]..a[n-1] a a zapíše do pole všechny prvky ze zásobníku najednou
copy a b b' zkopíruje pole a do pole b
forall a p - spustí p pro každý prvek pole

Strings

Příkaz Vstup Výstup Popis
string n s Vyrobí string délky n
anchorsearch s t post match true nebo s false Ověří, že t je začátkem s
search s t post match pre true nebo string false Hledá t v s
token s post token true nebo false Načte ze začátku s jeden token

length, get, put, getinterval, putinterval, copy, forall fungují stejně jako u polí

Kreslení

Příkaz Vstup Výstup Popis
newpath - - Vyrobí prázdnou cestu
currentpoint - x y
moveto x y - Posune se na x, y
rmoveto dx dy - Relativní posun - posune se o dx, dy
lineto x y - Udělá čáru na x, y
rlineto dx dy - Relativní čára - posune se o dx, dy a vyrobí tam čáru
arc x y r ang1 ang2 - Přidá kruhovou výseč (proti směru h. ručiček)
arcn x y r ang1 ang2 - Přidá kruhovou výseč (po směru h. ručiček)
curveto x1 y1 x2 y2 x3 y3 - Přidá Beziérovu křivku
rcurveto x1 y1 x2 y2 x3 y3 - Přidá Beziérovu křivku (relativní souřadnice)
closepath - - Uzavře aktuální cestu (spojí koncový a počáteční bod)
stroke - - Nakreslí aktuální čáru
fill - - Vybarví aktuální čáru
setlinewidth x - Nastaví šířkku čáry
currentlinewidth - x
setgray x - Nastaví barvu na šedou (0=černá … 1=bílá)
currentgray - x
setrgbcolor r g b - Nastaví barvu na RGB (hodnoty 0 až 1)
currentrgbcolor - r g b
gstate - - Uloží aktuální styl na zásobník stylů
grestore - - Načte styl ze zásobníku

Použitá notace

Zkratka
M značka
X, Y cokoliv
a, b pole
f boolean
i, n celé číslo
p procedura
r reálné číslo
s, t string
x, y čísla
: spodek zásobníku