PostScript II: De Operand Stack, Manipulaties en Wiskundige Operators

ArticleCategory: [Artikel Kategorie]

Software Development

AuthorImage:[Bild des Autors]

[Photo of the Author]

AuthorName:[Name des Autors]

Emre Demiralp

AboutTheAuthor:[Über den Autor]

Ik ben een student aan het American Robert College in Instanbul en, tegelijkertijd, een van de beheerders van de Computer Labs in de faculteit van Kunst en Wetenschappen van de Technische Universiteit van Instanbul. Het overdominerende systeem in deze labs is LINUX. Interesses: PovRay en Postscript, animatie, CD ontwerp, programmeren, holography enz... Linux gebruiker sinds 1994.

Abstract:[Zusammenfassung]

Druppel na druppel, wordt het een meer
-Turks Gezegde-.
De auteur beschrijft de operand stack van de PostScript taal. De stack manipulaties en wiskundige bewerkingen worden hier gepresenteerd. Dit artikel omvat niet alle eigenschappen van de Operand Stack. Toekomstige artikelen zullen hier verder op ingaan.

ArticleIllustration:[Titelbild des Artikels]

[Ilustration]

ArticleBody:[Der eigentliche Artikel]

Introductie

Dit is het tweede deel van een serie artikelen over PostScript. In dit artikel gaan we de stack operaties bekijken. De Operand Stack is waarschijnlijk het belangrijkste deel van PostScript. Toewijzingen, arithmetische of wiskundige operaties, lussen en logische operaties worden allemaal uitgevoerd in dit specifieke deel van het geheugen. Ja! De stack is een speciaal geheugen gebied, welke wordt gebruikt door PostScript om bijna alles te doen wat we PostScript vertellen. De stack houdt de informatie op orde zodat de laatst ingevoerde data als eerste er weer uit gaat. Je kunt dit visualiseren als een pijp waarvan een eind is dichtgestopt. Als je iets in deze pijp stopt, zal het alles wat er al in zat naar achteren schuiven om ruimte voor zichzelf te maken. Het laatst ingevoerde item zal zich dus altijd het dichtst bij het open einde van de pijp bevinden. De items op de stack kunnen strings, nummerieke constanten, sleutels, blokken, ... zijn.

Stack Manipulatie

Hoewel items gesorteerd worden op de stack, zijn er sommige stack operaties welke ons in staat stellen de items opnieuw te ordenen. Manipulaties worden uitgevoerd op een of meer items op de stack. De bewerkingen, bij definitie, bewerken item(s) op de stack. Sommige nemen parameters (operands in PostScript terminologie), afhankelijk van het soort bewerking. Als er parameters nodig zijn, dienen deze eerst op de stack te worden geplaatst. De bewerking voert dan zijn actie uit, afhankelijk van deze operands. Hier geven we een lijst vna deze operators met enige uitleg. Vervolgens geven we wat voorbeelden om meer details duidelijk te maken.

pop: Deze bewerking verwijderd het bovenste (laatst ingevoerde) element van de operand stack

exch: Deze operator verwisseld de bovenste twee elementen van de operand stack.

dup: Deze operator maakt een kopie van het laatst ingevoerde item van de operand stack en plaatst deze op de operand stack. In andere woorden, het dupliceerd het bovenste element.

copy: Deze operator neemt een integer operand (parameter) welke op de operand stack gegeven moet zijn voordat de bewerking gestart wordt. Als we n nemen voor deze integer parameter, wordt het commando gegeven als n copy. Als dit gebeurd is, wordt er een kopie gemaakt van de n bovenste elementen en als laatst ingevoerde elementen op de operand stack geplaatst. In ander woorden, copy is een set duplicatie bewerking.

index: Deze operator neemt een integer operand welke op de operand stack moet worden geplaatst voordat de bewerking actief wordt. Als we n nemen als de integer parameter dan wordt het commando gegeven als n index. Wanneer gebruikt, wordt er een kopie gemaakt van het nste element (van boven) op de operand stack en geplaatst als bovenste element. In andere woorden, index kan een intern element selecteren en diens kopie maken en bovenop de operand stack plaatsen. De index van elementen gebeurt van bovenaf en begint bij 0.

roll: Deze operator neemt twee integer parameters welke op de operand stack dienen geplaatst te worden, voordat het commando gebruikt. Als we m en n nemen voor deze parameters, wordt het commando gegeven als m n index. Hierbij geeft m aan hoeveel items "gerolled" worden, terwijl n het aantal rolls aangeeft. Een roll is zo gedefinieerd dat het bovenste element op de operand stack het m-ste element wordt, terwijl de set van m-1 elementen onder het bovenste element een plaatst naar boven opschuiven. Dit schema geldt totdat n gelijk wordt aan 1. Als het 2 zou zijn, vinden er twee rolls plaats. In andere woorden, m 2 roll is hetzelfde als m 1 roll m 1 roll. De parameter n kan negatieve waarden nemen. Als dit gebeurd, wordt de actie omgedraaid zoals die zou gebeuren als N positief is. Dit betekend dat het globale effect van het commando m n roll m -n roll neutraal is. Het laat de operand stack ongewijzigd. Het indexeren van de elementen begint bij het bovenste element met 0.

clear: Deze operator verwijderd alle elementen van de operand stack.

count: Deze operator telt de elementen op de operand stack. Het resultaat wordt als een nieuw element op de operand stack geplaatst. Als je dit nieuwe element niet wil, kun je het samengestelde commando count pstack pop, waar pop het nieuwe element, gecreëerd door count, verwijderd, nadat het resultaat van de telling wordt weergegeven door het gebruik van de bestands operator pstack.

mark: Deze operator plaatst een marktype (-marktype) element op de operand stack. Dit element kan gebruikt worden om de set elementen op de operand stack op te delen in subsets. Twee andere operators cleartomark en counttomark zoeken dit element voor hun acties. Als deze niet wordt gevonden wordt er een foutbericht gegeven.

cleartomark: Deze operator verwijderd alle elementen van het bovenste tot het eerste -marktype-. Dit -marktype- object wordt ook verwijderd. Als er geen marktype object op de operand stack kan worden gevonden, treedt er een foutmelding op.

counttomark: Deze operator telt de elementen, te beginnen bij het bovenste element, totdat het marktype object wordt gevonden. Het resultaat is een integer waarde die op de operand stack wordt geplaatst als het laatste element. Het eerste gevonden marktype element wordt niet meegeteld. Als er geen marktype element op de operand stack wordt gevonden, zal PostSript gaan klagen en gebeurt er niets.

Laten we nu iets zeggen over de stack. Als je bovenstaande operators in actie wilt zien, moet je eerst
de PostScript interpreter starten. Zoals genoemd in het eerste artikel, gebruikt de Linux wereld een publiek beschikbare interpreter, ghostscript. Ghostscript kan op verschillende manieren geactiverd worden, door bepaalde parameters mee te geven op de opdrachtregel. De gebruikelijke manier is om gewoon gs in de X Window omgeving te gebruiken. Soms werkt dit niet door een configuratie fout in X. Er wordt dan een foutmelding gegeven over de onmogelijkheid een bruikbare grafische console te creëeren. Dan moeten deze problemen worden opgelost, eventueel kun je ghostscript vertellen het apparaat x11 te gebruiken. Hiervoor gebruik je gs -sDEVICE=x11. Dit of gewoon gs (als het werkt) maakt een leeg venster met een witte achtergrond, welke wordt gebruikt voor de weergaven tijdens de sessie. Daar de weergaven in dit artikel verder niet gebruikt worden, hebben we dit venster niet nodig, het is mogelijk deze achterwege te laten. Hiervoor kun je de interpreter starten zonder venster door de -dNODISPLAY parameter mee te geven op de opdrachtregel na gs of gs -sDEVICE=x11. Als dit gebeurd, wordt er een copyright header weergegeven, gevolgd door de ghostscript promptGS> aan het begin van een nieuwe regel. Op dit punt is ghostscript klaar voor je commando's. De operand stack is leeg.

Om de inhoud van de operand stack te zien, kun je bestands operator gebruiken, pstack. Dit wordt een bestands operator genoemd omdat het informatie over de inhoud van de stack naar de standaard uitvoer bestand schrijft, standaard is dit het scherm. Als je dit commando op de prompt geeft, wordt er niets weergegeven en een nieuwe GS> prompt verschijnt aan het begin van de nieuwe regel. Dit betekend dat de operand stack leeg is.

Om elementen op de operand stack te plaatsen kun je de elementen opgeven op de prompt. Als je bijvoorbeeld 1 als een element wil plaatsten, type je gewoon 1 op de prompt. Hierna verschijnt er een nieuwe prompt op de volgende regel. Maar, deze keer is de prompt niet GS>, maar GS<1>. Deze nieuwe vorm van de prompt geeft het aantal elementen op de operand stack weer. Dus, als je GS<123> in je ghostscript sessie ziet, betekend dit dat er 123 elementen zich op de operand stack bevinden.

Je kunt in een enkele poging meerdere elementen op de operand stack plaatsen. Hiervoor type je alle elementen achtereenvolgens, maar gescheiden door een spatie. Als je bijvoorbeeld 1 2 3 4 5 6 op de prompt geeft, worden de elementen 1, 2, 3, 4, 5 en 6 op de operand stack geplaatst. Als je hierna het pstack gebruikt, worden de elementen in een verticale volgorde weergegeven, zodat het laatst opgegeven element het eerst verschijnt. De weergave van dit commando ziet er als volgt uit:

GS>1 2 3 4 5 6
GS<6>pstack
6
5
4
3
2
1
GS<6>
Het is ook mogelijk om elementen op de operand stack te plaatsen en de inhoud van de stack te zien, in een commando. Alles wat je hoeft te doen is:
GS>1 2 3 4 5 6 pstack
6
5
4
3
2
1
GS<6>
Tot nog toe gebruikten we nummers om elementen te plaatsen. Nummers zijn niet het enige type element, het is mogelijk om andere soorten elementen zoals variabelen of sleutels (keys), strings, blokken, enz te gebruiken. Deze zullen we later in meer detail bekijken. We moeten nu echter iets zeggen: als je probeert om, bijvoorbeeld, een enkel karakter a of een string abc te plaatsen, treedt er een foutmelding op. Dit is omdat PostScript deze dingen niet kan begrijpen. Als je een karakter of een string wilt opgeven, moet je deze insluiten in (). Hier spraken we over speciaal element type, welke is genaamd marktype. Om dit te zien, gebruiken we de volgende sessie als een voorbeeld:
GS>1 2 3 mark 4 5 6 pstack
6
5
4
-marktype-
3
2
1
GS<7>
Nu gaan we een paar voorbeelden zien van de operators van de operand stack manipulaties. Ik geef een voorbeeld sessie om te laten zien hoe deze operators zich gedragen en zou deze sessie graag sluiten zonder verdere uitleg.
GS>1 2 3 mark 4 5 6 pstack
6
5
4
-marktype-
3
2
1
GS<7>pop pstack
5
4
-marktype
3
2
1
GS<6>exch pstack
4
5
-marktype
3
2
1
GS<6>dup pstack
4
4
5
-marktype-
3
2
1
GS<7>2 copy pstack
4
4
4
4
5
-marktype
3
2
1
GS<9>5 index pstack
-marktype-
4
4
4
4
5
-marktype
3
2
1
GS<10>cleartomark cleartomark pstack
3
2
1
GS<3>3 1 roll pstack
2
1
3
GS<3>count pstack
3
2
1
3
GS<4>mark 7 8 pstack
8
7
-marktype-
3
2
1
3
GS<7>counttomark pstack
2
8
7
-marktype-
3
2
1
3
GS<8>clear pstack
GS>

Wiskundige Operaties

Behalve de manipulatie operators op de operand stack van PostScript zijn er ook een aantal rekenkundige en mathematische operaties. Hieronder worden deze operators gegeven. Er zijn geen voorbeelden. Het wordt aan de lezer over gelaten de maken, uitgerust met bovenstaande voorbeeld sessie.

add: Dit commando neemt twee nummerieke parameters, welke gebruikt worden voor het optellen. Als deze waarden zeg maar m en n zijn, wordt het commando gegeven als m n add. Als dit gebeurd, wordt eerst m en vervolgens n op de operand stack geplaatst. De acite van de add operator op deze twee bovenste elementen van de operand stack is de laatste stap. Het creëert een nieuw element dat gelijk is aan de som van m en n. Als de operatie compleet is, blijven m en n niet op de operand stack. In plaats daarvan wordt het resultaat het bovenste element op de operand stack.

div: Dit commando neemt twee nummerieke parameters, welke gebruikt worden voor de deling. Gesteld dat deze parameters m en n zijn, wordt het commando gegeven als m n div. Het mechanisme voor de bewerking is het zelfde als add. De deling geschied op het floating point (drijvende comma) rekenkundig niveau. Als de operatie compleet is, blijft alleen het resultaat over op de operand stack als een nieuw element. m en n blijven niet bewaard.

idiv: Dit commando neemt twee nummerieke parameters, welke gebruikt worden voor de integer delings bewerking. Als we m en n als waarden nemen, wordt het commando gegeven als m n idiv. Alles is hetzelfde als met div, behalve het deel niveau. Het is een integer rekenkundige bewerking. Als de parameters geen integers zijn, werkt het ook.

mod: Dit commando neemt twee integer parameters. Het evalueerd het overblijfsel van de deling van de eerste parameter door de tweede. Als een van de parameters geen integer is dan faalt de bewerking. Het resultaat wordt als enige bewaard op de operand stack.

mul: Zelfde als add, div. Het is een binair commando dat twee nummerieke waarden neemt. Het resultaat is de vermenigvuldiging van de parameters en wordt bewaard als een nieuw element op de operand stack.

sub: Zelfde als add, div, mul. Het enige verschil is het type bewerking. Het trekt de waarde van de tweede parameter van de waarde van de eerste af. Parameters en resultaat zijn nummerieke waarden en het resultaat wordt bewaard op de operand stack als de bewerking compleet is.

exp: Dit is een binaire mathematisch commando. Het neemt twee parameters. De eerste is de basis en de tweede is exponent. De parameters moeten binnen de limitaties van de exponentiële bewerking vallen. Het resultaat is een floating point nummer dat als nieuw element wordt bewaard op de operand stack.

atan: Dit is een andere mathematische commando voor de evaluatie van een hoek. De hoek wordt gegeven in graden tussen 0 en 360. Het neemt twee parameters. De ratio van de eerste parameter tot de tweede is gelijk aan de tangens van de te berekenen hoek. Elk van de parameters mag nul zijn, maar niet beide. De tekens van de parameters bepalen het quadrant waar het resultaat zal liggen. De positieve waarden in de eerste parameter corresponderen met een postitieve y waarde. Positieve waarden in de tweede parameter betekenen een positieve x waarde.

abs: Dit is een unary (1) mathematisch commando. Het neemt een parameter waarvan de absolute waarde het resultaat is. Net als hierboven wordt het resultaat opgeslagen als een nieuw element op de operand stack. (1) Unary wil zeggen dat de functie of bewerking maar een parameter neemt en ook 1 waarde teruggeeft.

neg: Dit veranderd het teken van zijn enige argument. Het is een unary artithmetisch commando.

ceiling: Dit is een unary commando, dat de integer waarde evalueerd die het dichts bij zijn argument van boven ligt.

floor: Dit is een unary commando dat de integer waarde opzoekt die het dichts bij zijn argument ligt, van beneden.

round: Dit is een unary commando dat de integer waarde opzoekt die het dichtst bij zijn argument ligt.

truncate: Dit is een unary commando dat het fractionele deel van zijn argument verwijder.

sqrt: Dit is een unary commando dat de wortel van zijn argument berekend.

cos: Dit is een unary commando dat de cosinus van zijn argument berekend. Het argument wordt verwacht in graden.

sin: Dit is een unary commando dat de sinus van zijn argument berekend. Het argument wordt verondersteld in graden te zijn gegeven.

ln: Dit is een unary commando welke het natuurlijke logarithme van zijn argument berekend.

log: Dit is een unary commando die de basis-10 logatithme van zijn argument berekend.

Voordat we het artikel hier beëindigen, is hier nog een opmerking. Hoewel we het eerder genoemd hebben, wellicht impliciet, kunnen de parameter(s) (operands in PostScript terminologie) van een commando nogal onprettige problemen opleveren. Het commando (of operator in PostScript terminologie) zoek zijn parameter(s) in de operand stack. Wanneer gevonden, worden ze gebruikt door het commando en verwijderd van de operand stack. Het geven van een commmando zonder de benodigde parameter(s), of het nu met opzet of per ongeluk gaat, zal een melding opleveren over de parameter(s) die zich bovenin de operand stack bevinden, als deze niet bruikbaar zijn voor het parameter type, of de bovenste elementen van de operand stack worden verwijderd. De gebruiker dient erg voorzichtig te zijn met dit punt.

Alvorens deze presentatie af te sluiten, raden we aan om gecompliceerdere en omvangrijke programma's te schrijven, als men tenminste verder wil met PostScript. In de volgende artikelen van deze serie, zullen meer details worden gegeven over de PostScript taal. Alle vragen en commentaren over onze presentaties zijn welkom.

Gecontroleerd door Jorge M. Paulo en Jose Quesada