Hlavní navigace

Slovníky a zásobníky v PostScriptu

12. 7. 2007
Doba čtení: 10 minut

Sdílet

V předchozích článcích o jazyce PostScript jsme si řekli, že se při zápisu programů neobejdeme bez použití zásobníku. Ve skutečnosti se v PostScriptu pracuje celkem s pěti zásobníky, jejichž význam si vysvětlíme. Také si povíme, jak pracovat se slovníky, které jsou v jiných jazycích známé pod názvem asociativní pole či hashmapy.

Obsah

1. Pětice zásobníků a způsob jejich využití
2. Zásobník operandů
3. Zásobník slovníků
4. Zásobník spustitelných objektů
5. Zásobník grafických stavů
6. Zásobník ořezových cest
7. Odkazy na další informační zdroje
8. Obsah dalšího pokračování tohoto seriálu

1. Pětice zásobníků a způsob jejich využití

Interpreter PostScriptu pracuje celkem s pěti typy zásobníků. Jedná se o zásobník operandů (operand stack), zásobník slovníků (dictionary stack), zásobník spustitelných objektů (execution stack), zásobník grafických stavů (graphics state stack) a konečně zásobník ořezových cest (clipping path stack). V předchozích částech tohoto seriálu, ve kterých jsme si ukazovali krátké programy vytvořené v PostScriptu, jsme převážně pracovali se zásobníkem operandů (právě zde se uplatnil zápis aritmetických a logických operací pomocí převrácené polské notace – RPN) a interpreter nepřímo pracoval také se zásobníkem slovníků a zásobníkem spustitelných objektů. V dalším textu si popíšeme, k jakým operacím je možné jednotlivé zásobníky použít.

2. Zásobník operandů

Zásobník operandů (operand stack) již velmi dobře známe. Tento zásobník je použit především při vyhodnocování aritmetických a logických výrazů pomocí RPN (Reverse Polish Notation). Kromě toho se přes zásobník operandů předávají parametry systémovým i uživatelským funkcím (například se jedná o příkaz moveto, který ze zásobníku vyčte dvě číselné hodnoty představující souřadnice bodu) a tyto funkce mohou na zásobník operandů vracet nějaké výsledky. I operátory/příkazy pro tvorbu programových smyček tento zásobník využívají – jak pro specifikaci počtu průběhů smyčky a mezních hodnot počitadla, tak i pro průběžné ukládání aktuální hodnoty počitadla. Pro manipulaci s hodnotami uloženými na tomto zásobníku slouží operátory dup, pop, exch, copy, roll, count, clear, index, mark, counttomark a cleartomark, jejichž bližší popis je uveden v následující tabulce:

Operátor Význam operátoru
clear vymazání všech objektů ze zásobníku (vyprázdnění zásobníku operandů)
count na zásobník operandů se uloží celé číslo reprezentující počet položek v něm uložených (aktuální hloubka zásobníku)
copy na zásobníku operandů se zduplikuje posledních n položek (n je uloženo na vrcholu zásobníku)
dup duplikace (kopie) hodnoty uložené na vrcholu zásobníku operandů
pop opak předchozího operátoru – odstranění položky z vrcholu zásobníku (ve Forthu se jednalo o příkaz „drop“ se stejným významem)
exch prohození dvou položek uložených na nejvyšších dvou místech zásobníku operandů, bez ohledu na datový typ položek
index na vrchol zásobníku operandů se zkopíruje n-tá položka
mark na zásobník se uloží značka (speciální hodnota použitá v následujích dvou operátorech)
cleartomark vymazání nejvyšších položek na zásobníku až po vloženou značku
counttomark na zásobník se uloží počet všech nalezených položek až po vloženou značku

Mezi aritmetické operátory a funkce, které využívají zásobník operandů pro získání hodnot operandů a vrací na zásobník výsledek dané operace, patří:

Operátor Význam operátoru
add součet dvou hodnot uložených na nejvyšších dvou místech zásobníku operandů
sub rozdíl dvou hodnot uložených na nejvyšších dvou místech zásobníku operandů
mul součin dvou hodnot uložených na nejvyšších dvou místech zásobníku operandů
div podíl dvou hodnot uložených na nejvyšších dvou místech zásobníku operandů
idiv podíl dvou celočíselných hodnot
mod výpočet zbytku po dělení dvou celočíselných hodnot
abs na zásobník se vrátí absolutní hodnota přečtená z jeho nejvyššího místa (TOS)
neg otočení znaménka hodnoty uložené na nejvyšším místě zásobníku operandů
ceiling zaokrouhlení hodnoty uložené na nejvyšším místě zásobníku operandů směrem nahoru
floor zaokrouhlení hodnoty uložené na nejvyšším místě zásobníku operandů směrem dolů
round zaokrouhlení hodnoty uložené na nejvyšším místě zásobníku operandů k nebližší celočíselné hodnotě
truncate odříznutí desetinné části hodnoty uložené na nejvyšším místě zásobníku operandů
sqrt výpočet druhé odmocniny hodnoty uložené na nejvyšším místě zásobníku operandů
atan výpočet arkustangenty z podílu dvou hodnot chápaných jako údaj ve stupních (odpovídá funkci atan2() v céčku)
sin sinus hodnoty uložené na TOS (zadaný úhel je ve stupních, ne v radiánech)
cos kosinus hodnoty uložené na TOS (zadaný úhel je ve stupních, ne v radiánech)
ln přirozený logaritmus hodnoty uložené na TOS
log desítkový logaritmus hodnoty uložené na TOS
epx výpočet xy, obě požadované hodnoty jsou uložené na zásobníku operandů
rand vygenerování pseudonáhodného celého čísla (typu int) a uložení na TOS
srand inicializace generátoru pseudonáhodných čísel (RND) z hodnoty uložené na TOS
rrand vrácení inicializační hodnoty generátoru pseudonáhodných čísel (RND) na TOS

Zkratkou TOS je v předchozích dvou tabulkách myšlena nejvyšší obsazená pozice na zásobníku operandů; samotná zkratka má význam Top Of Stack a používá se mj. i v literatuře o programovacím jazyku Forth.

3. Zásobník slovníků

Zásobník slovníků (dictionary stack) může obsahovat – jak již ostatně jeho jméno napovídá – pouze objekty, které jsou typu slovník (v dalším textu se dozvíme, že slovníky nejsou nic jiného než asociativní pole či hashmapy známé z dalších programovacích jazyků). Interpreter PostScriptu z tohoto zásobníku čte hodnoty ve všech případech, kdy při procházení programu nalezne nějaké slovo či symbol. Může se jednat o systémový příkaz, uživatelskou funkci, jméno fontu, který byl načten příkazem findfont atd. Systémové příkazy jsou uloženy ve slovníku nazvaném system dictionary, uživatelské příkazy ve slovníku user dictionary, jména fontů ve slovníku fontů atd. Pro získání těchto slovníků je možné použít následující příkazy/operátory:

Operátor Význam operátoru
systemdict na TOS zásobníku operandů se uloží odkaz na systémový slovník
globaldict na TOS zásobníku operandů se uloží odkaz na globální slovník (globální virtuální paměť – VM)
userdict na TOS zásobníku operandů se uloží odkaz na uživatelský slovník (lokální virtuální paměť)
currentdict na TOS zásobníku operandů se uloží právě aktivní slovník (ten, který je na TOS zásobníku slovníků). Na tento zásobník se slovníky ukládají pomocí operátoru begin

Pro manipulaci s celými slovníky nebo „pouze“ s jejich obsahem je možné použít mnoho operátorů, které jsou vypsány v následující tabulce:

Operátor Význam operátoru
length vrací počet položek uložených ve slovníku, jehož odkaz je na TOS zásobníku operandů
maxlength vrací maximální počet položek, které je možné uložit do slovníku, jehož odkaz je na TOS zásobníku operandů
countdictstack vrací počet položek uložených na zásobníku slovníků
cleardictstack odstraní všechny odstranitelné slovníky ze zásobníku slovníků
dict vytvoření nového slovníku, jméno slovníku a jeho kapacita je uložena na TOS zásobníku operandů
<< začátek vytváření slovníku
>> konec vytváření slovníku
begin na vrchol zásobníku slovníku se uloží odkaz na slovník získaný z TOS zásobníku operandů
end z vrcholu zásobníku slovníků se odstraní zde uložený odkaz na slovník
def uložení dvojice klíč-hodnota do aktivního slovníku (klíč a hodnota jsou uloženy na nejvyšších dvou místech zásobníku operandů)
store přepis dvojice klíč-hodnota novou dvojicí (nevznikají duplicity)
load prohledání zásobníku slovníků a vrácení hodnoty odpovídající klíči (ten je uložen na TOS zásobníku operandů)
get podobné operátoru load, ale prohledává se slovník uložený na zásobníku operandů
put na slovník uložený v zásobníku operandů se uloží dvojice klíč-hodnota
undef odstranění dvojice klíč-hodnota ze slovníku, jehož odkaz je uložen na zásobníku operandů
known test, zda slovník obsahuje daný klíč
forall pro každý prvek ve slovníku se zavolá určená procedura

Při práci se slovníky se nejčastěji používají operace get, put, undef a known. Všechny operace předpokládají, že je identifikátor (či odkaz) na požadovaný slovník uložený na zásobníku operátorů. Kromě toho se na tento zásobník ukládají i další potřebné parametry, tj. klíče a k nim přiřazené hodnoty.

Operátor get očekává parametry (slovník, klíč), operátor put parametry (slovník, klíč, hodnota) a operátor knownundef parametry (slovník, klíč). Výsledek operace je uložen na TOS zásobníku operandů. Buď se jedná o nalezenou hodnotu (get), nebo o hodnotu true/false (known). Do světa funkcionálních jazyků nás zavádí operátor forall, pomocí něhož je možné na všechny prvky uložené ve slovníku zavolat zadanou proceduru bez nutnosti explicitního zápisu smyčky. Očekávané parametry tohoto operátoru jsou (slovník, procedura).

4. Zásobník spustitelných objektů

Zásobník spustitelných objektů (execution stack) je používán interpreterem PostScriptu pro úschovu objektů, které jsou v dané chvíli spuštěny. V tomto zásobníku bývají typicky uložené volané, tj. spuštěné procedury a identifikátory otevřených souborů. Jakmile je zavolána nějaká procedura, je reference na ni (plus bod návratu) uložen na zásobník spustitelných objektů a při ukončení procedury se její reference z tohoto zásobníku odstraní, čímž se na vrchol zásobníku (TOS – Top Of Stack) vrátí původní (volající) procedura.

V určitém ohledu, zejména způsobem použití, se tento zásobník podobá zásobníku návratových adres (Return Stack) použitý ve Forthu. Narozdíl od Forthu však není možné obsah tohoto zásobníku přímo modifikovat programovým kódem (ve Forthu bylo možné přenášet údaje ze zásobníku návratových adres do zásobníku operandů a naopak).

5. Zásobník grafických stavů

Na zásobník grafických stavů (graphics state stack) je možné uložit aktuální grafický stav a po provedení nějaké operace (třeba kreslení jiným stylem čáry) se tento stav může ze zásobníku obnovit. Tento zásobník se v praxi používá poměrně často, zejména proto, že součástí grafického stavu je i CTM, tj. current transformation matrix – transformační matice používaná pro převod uživatelských souřadnic na souřadnice zařízení.

Grafický stav je možné na zásobník grafických stavů uložit příkazem gsave a obnovit pomocí příkazu grestore. V novějších verzích PostScriptu je možné z grafického stavu vytvořit objekt a pracovat s ním nezávisle na zásobníku grafických stavů. Pro tento účel slouží operátory gstate (vytvoření grafického objektu), currentgstate (kopie grafického stavu do vytvořeného objektu) a setgstate (zpětná kopie dat z objektu, ve kterém byl grafický stav uložený). V grafickém stavu jsou mj. uloženy tyto informace:

Název Význam
CTM aktuálně používaná transformační matice
position souřadnice aktuálního bodu (konce cesty), nastaveno například pomocí operátoru moveto
path interní identifikátor právě vytvářené cesty
clipping path interní identifikátor právě používané ořezové cesty
color space barvový prostor zařízení
color aktuálně nastavená barva vykreslování cesty nebo jejího vnitřku
font slovník tvarů jednotlivých znaků právě používaného fontu
line width šířka čáry konstruované cesty
line cap způsob ukončení širokých čar v cestě
line join způsob napojení širokých čar v cestě
dash pattern styl vykreslovaných čar
color rendering způsob převodu barev z barvového prostoru CIE-xy do interního barvového prostoru zařízení
overprint způsob vykreslování separovaných barev
black generation procedura, která je použita pro výpočet černé barvy při převodu z RGB do CMYK
undercolor removal procedura použitá ke kompenzaci barev při převodu z RGB do CMYK
halftone procedura či slovník použitý při halftoningu (nahrazování barevných přechodů vzorkem)
flatness tolerance zadaná v pixelech, která je použita při vykreslování Bézierových křivek

6. Zásobník ořezových cest

Zásobník ořezových cest (clipping path stack) je použit k úschově a následnému výběru tvarů takzvaných ořezových cest (clipping path). Ořezová cesta je do tohoto zásobníku vložena příkazem clipsave a obnovena příkazem cliprestore. Kromě těchto dvou příkazů je možné zkombinovat ořezovou cestu s cestou právě konstruovanou (příkaz clip), popř. nahradit vytvářenou cestu kopií ořezové cesty (příkaz clippath).

Implicitní ořezová cesta zkonstruovaná interpreterem před započetím vytváření tiskové strany má tvar obdélníka, jehož hrany odpovídají okrajům tiskové strany. Jinými slovy to znamená, že je každá cesta či jiný vykreslovaný tvar ořezán přesně na okraji tiskové strany. Ořezové cesty je možné použít i při zobrazování bitmap, tj. rastrových obrázků. Použití této techniky, která má v praxi velké možnosti uplatnění, si ukážeme v následující části tohoto seriálu.

7. Odkazy na další informační zdroje

Práce se zásobníky je v PostScriptu podobná jako v dalších programovacích jazycích založených na převrácené polské notaci (RPN). Proto v odkazech na literaturu uvádím i materiály, které se týkají snad nejznámějšího zásobníkového jazyka – Forthu.

UX DAy - tip 2

  1. Adobe Systems: PostScript Language Reference Manual, The Red Book,
    Adobe Systems Incorporated, 2nd ed., Addison Wesley 1990.
  2. Adobe Type 1 Font Format (včetně ukázek s použitím smyček),
    Addison-Wesley
  3. PostScript Language Program Design,
    Addison-Wesley 1990, ISBN 0–201–14396–8
  4. PostScript Language Reference Manual,
    Addison-Wesley 1990, ISBN 0–201–18127–4
  5. PostScript Language Tutorial and Cookbook,
    Addison-Wesley 1990, ISBN 0–201–10179–3
  6. Pavel Herout:
    PostScriptové fonty pro ty, co o nich moc nevědí
  7. Pavel Tišnovský:
    Programovací jazyk Forth,
    /clanky/progra­movaci-jazyk-forth-a-zasobnikove-procesory
  8. http://zforth­.com/ – takzvaný The Forth Programming Webring, počátek řetězce stránek věnovaných Forthu a příbuzným tématům. Zajímavé je, že tento server je vytvořen pomocí systému zHTTP, který je napsaný v dialektu programovacího jazyka Forth nazvaného zForth.
  9. http://www.for­th.com/ – úvodní stránka firmy Forth Inc., která vytváří komerční verze programovacího jazyka Forth spolu s propracovaným vývojovým prostředím, na stránce lze nalézt i odkaz na známý SwiftForth. Spoluzakladatelem této firmy je Chuck Moore.
  10. http://en.wiki­pedia.org/wiki/For­th_programmin­g_language – stránka Wikipedie o programovacím jazyku Forth.
  11. http://en.wiki­pedia.org/wiki/Chuc­k_Moore – stránka Wikipedie o Chucku Moorovi, vynálezci Forthu.
  12. http://home.e­arthlink.net/~mrob/p­ub/lang_srom.html – porovnání programovacích jazyků podle názoru programátorů.
  13. http://www.jwdt­.com/~paysan/gfor­th.html – GForth (GNU Forth)
  14. http://www.for­th.com/resources/e­volution/index­.html – The Evolution of Forth – velmi dobře zpracovaná historie Forthu.

8. Obsah dalšího pokračování tohoto seriálu

V následující části tohoto seriálu dokončíme povídání o PostScriptu. Řekneme si, jakým způsobem je možné v PostScriptu (což je původně vektorový formát) používat bitmapy, tj. jak lze kombinovat vektorovou grafiku s grafikou rastrovou. Uvidíme, že v PostScriptu je možné bitmapy ukládat jak bezeztrátově, tak i pomocí ztrátové komprimace založené například na již dříve popsaném algoritmu JPEG.

Byl pro vás článek přínosný?

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.