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 |