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í null y |
[ |
- | 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 |