Emre Demiralp About the author:I am a student in Istanbul American Robert College, and at the same time, one of the administrators of the Computer Labs in Faculty of Arts and Sciences in Istanbul Technical University. The over dominating operating system in these labs is LINUX. Interests: PovRay and PostScript, animation, CD design, programming, holography etc.. Linux user since 1994. Content: |

Abstract:

The author describes the operand stack of the PostScript language. The stack manipulations and mathematical operators are presented here. This article does not cover all properties of the operand stack. The future articles will continue to tell about it.Drop after drop, it becomes a lake

-Turkish Proverb-.

This is the second of a series of articles about PostScript. The main purpose of this article is to mention the stack operations. The operand stack is perhaps the most important part of PostScript. Assignments, arithmetical or mathematical operations, loops and logical operations are all handled in this specific piece of memory. Yes! The stack is a special memory region which is used by PostScript to execute almost everything we want PostScript to do. The stack keeps the information in an order such that the last entered data exits first. You can visualize this as a pipe whose one end is closed. When you put something into this pipe, it will push all existing things inside the pipe toward the closed end to make room for itself. So the last entered item will always be the closest one to the open end. The items in the stack can be strings, numerical constants, keys, blocks, ...

Although items are ordered in the stack, there are some stack operations which allow us to reorder the items. Manipulations are applied to one or more items in the stack. The operators, by definition, manipulate item(s) in the stack. They may or may not need parameters (operands in PostScript terminology) depending on the character of the manipulation. If they need the parameter(s) then these must be pushed into the stack first. The operator then takes action regarding these operands. Here we give a list of these operators with sufficient explanations. Then we give some examples to illustrate more details.

**pop: **This operator discards the topmost element (last entered)
of the operand stack

**exch: **This operator exchanges the two topmost elements of the
operand stack

**dup: **This operator creates a copy of the last entered element
of the operand stack and pushes it into the operand stack. In other words,
it duplicates the topmost element.

**copy: **This operator needs an integer operand (parameter) which
must be given to the operand stack before the operator acts. If we say
`n` for this integer parameter then the command will be given as
`n copy`. When this is done, the copy of the set of `n` topmost
elements will be created and located into the operand stack as the last
entered elements. In other words, `copy` is a set duplication operator.

**index: **This operator needs an integer operand which must be given
to the operand stack before the operator acts. If we say `n` for
this integer parameter then the command will be given as `n index`.
When this is done, the copy of `n`-th topmost element will be created
and located into the operand stack as the last entered element. In other
words, `index` can select an internal element and create and locate
its copy into the operand stack. The indexing of the elements starts from
the topmost element with `0`.

**roll:** This operator needs two integer parameters which must be
given to the operand stack before the operator acts. If we say `m`
and `n` for these integer parameters then the command will be given
as `m n index`. Here, `m` denotes how many elements will
be rolled while `n` characterizes the number of the rolls. One roll
is defined in such a way that the topmost element of the operand stack
becomes the `m`-th element while the set of `m-1` elements
below the topmost element is shifted one place to top. This scheme is valid
when `n` is equal to 1. If it would be 2 then two consecutive rolls
will be occurred. In other words `m 2 roll` is same with `m 1
roll m 1 roll`. The parameter `n` can take negative values.
If this occurs, it reverses the action that happens when `n` is
positive. This means that the global effect of the command `m n roll
m -n roll` is neutral. It leaves the operand stack unchanged. The indexing
of the elements starts from the topmost element with `0`.

**clear: **This operator discards all elements of the operand stack.

**count: **This operator counts the elements of the operand stack.
The result is pushed to the operand stack as a new element. If you do not
want this new element then you can issue the composite command `count
pstack pop` where `pop` removes the new element created by `count`
after the result of the counting is displayed through the action of the
file operator `pstack.`

**mark: **This operator puts a marktype (`-marktype-`) element
into the operand stack. This element can be used to divide the set of elements
in the operand stack into subsets. Two other operators `cleartomark`
and `counttomark` seek this element for their actions. If not found
then an error message is issued.

**cleartomark: **This operator removes all elements from the topmost
one to the first `-marktype-`. This `-marktype-` object is
also removed. If there is no marktype object in the operand stack then
an error message is issued.

**counttomark: **This operator counts the elements starting from
the topmost element until the marktype object is encountered. The result
which is an integer value is pushed into the operand stack as the last
element. The first encountered marktype element is not included in the
result. If there is no marktype element in the operand stack then PostScript
complains and does nothing.

Let us now say something about the stack. If you want to see the above
operators in action, you must first activate

the PostScript interpreter. As mentioned in the first article,
the Linux world uses a publicly available interpreter, `ghostscript`.
Ghostscript can be activated in different ways by giving appropriate parameters
in the command line. The usual way is just to enter `gs` in the
X Window environment. Sometimes this may not work due to some configuration
problems in X .An error message about the incapability for creating
a convenient graphic console is displayed . Then these problems must be
solved or you may force ghostscript to use the device `x11`. For
this purpose you enter `gs -sDEVICE=x11`. This or just plain `gs`
(if it works) creates a white background blank window which is used for
displays to be created during the session. Since the displays are not involved
in this article we do not need this window and it is possible to get rid
of it. For this, the ghostscript interpreter can be activated without display
by entering the `-dNODISPLAY` parameter in the command line after
`gs` or `gs -sDEVICE=x11`. If this is done then a copyright
header is displayed followed by the ghostscript prompt `GS>`
at the beginning of a new line. At this point, ghostscript is ready for
your commands. The operand stack is empty.

To see the content of the operand stack you can use a file operator,
`pstack`. This is called a file operator because it sends information
about the content of the stack to the standard output file which is the
screen by default. If you enter this command at the prompt then nothing
is displayed and a new `GS>` prompt appears at the beginning of
the newline. This means that the operand stack is empty.

To enter elements into the operand stack you can enter the elements
at the prompt. For example if you want to enter `1` as an element
then you just enter `1` at the prompt. After this a new prompt is
created at the beginning of the next line. But, this time, prompt is not
`GS>`. It is `GS<1>`. This new form of the prompt reflects
the number of the elements in the operand stack. So, if you have `GS<123>`
at any moment in your ghostscript session then this means that there are
123 elements in the operand stack.

You can enter more than one element into the operand stack in one single
attempt. For this, you should type all the elements consecutively ,but
separated by a blank space. For example, if you enter `1 2 3 4 5 6`
at the prompt then the elements `1`, `2`, `3`, `4`,
`5`, `6`, are pushed into the operand stack respectively.
If you issue `pstack` after this, then the elements are displayed
in vertical order such that the last entered element is displayed first.
The display of this two command session can be given as follows:

It is also possible to enter elements into the operand stack and to see the contents of the stack in one single attempt. All you have to do is to giveGS>1 2 3 4 5 6 GS<6>pstack 6 5 4 3 2 1 GS<6>

Until now we used numbers for entering elements. Numbers are not the only type of elements, it is possible to enter other kind of elements like variables or keys, strings, blocks etc. We shall mention them later in detail. However we should say something now: If you attempt to enter for example, just a single characterGS>1 2 3 4 5 6 pstack 6 5 4 3 2 1 GS<6>

Now we are going to see some examples for the operators of operand stack manipulations. I give an example session to show how these operators act and I would like to close this section without any further explanation.GS>1 2 3 mark 4 5 6 pstack 6 5 4 -marktype- 3 2 1 GS<7>

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>

Aside from the manipulation operators on the operand stack of PostScript there are some arithmetical and mathematical operators as well. Below, these operators are given. There will be no examples. They are left up to the reader who should now be able to create them ,being equipped with the example session given above.

**add: **This command needs two numerical parameters whose values
enter the addition operation. If these values are, say `m` and `n`,
then the command is given as `m n add`. When this is done, first
`m` then `n` is pushed into the operand stack. The action
of the `add` operator onto these two topmost elements of the operand
stack is the final stage. It creates a new element with the value which
is equal to the sum of `m` and `n`. When the operation is
completed `m` and `n` is not held in the operand stack. Instead,
the result becomes the topmost element of the operand stack.

**div: **This command needs two numerical parameters whose values
enter the division operation. If these values are, say `m` and `n`,
then the command is given as `m n div`. The operation mechanism
is same with the one for `add`. Division operation is at the floating
point arithmetic level. After the operation is done only the result remains
in the operand stack as a new element. `m` and `n` is not
maintained.

**idiv: **This command needs two numerical parameters whose values
enter the integer division operation. If these values are, say `m`
and `n`, then the command is given as `m n idiv`. Everything
is the same with `div` except the division level. It is an integer
arithmetic division operation. If the parameters are not integers it works
too.

**mod: **This command needs two integer parameters. It evaluates
the remainder of the division of the first parameter by the second. If
any one of the parameters is not an integer then it fails to work. The
result is the only maintained value in the operand stack after the operation
takes place.

**mul: **Same as add, div. It is a binary operator which needs two
numerical values. The result is the multiplication of the parameters and
is maintained as a new element in the operand stack.

**sub: **Same as add, div, mul. The only difference is the operation
type. It subtracts the value of the second parameter from the value of
the first. Parameters and the result are numerical values and the result
is maintained in the operand stack after the operation is complete.

**exp: **This is a binary mathematical operator. It needs two parameters.
The first is the base and the second is the exponent. It raises the value
of the base to the power whose value is the exponent. The parameters must
be within the limitations for the exponentiation operation. The result
which is a floating point number that is maintained as a new element in
the operand stack.

**atan: **This is another binary mathematical operator for the evaluation
of an angle. The angle is given in degrees between `0` and `360`.
It needs two parameters. The ratio of the first parameter to the second
equals the tangent of the angle to be evaluated. Any one of the parameters
may be zero but both cannot be given zero values. The signs of the
parameters determine the quadrant where the result will lie. The positive
values in the first parameter corresponds to positive `y` plane.
Whereas, the positive values in the second parameter mean positive `x`
plane.

**abs: **This is a unary mathematical operator. It needs only one
parameter whose absolute value is the result. Similarly as above, the result
is maintained as a new element in the operand stack.

**neg: **This changes the sign of its only argument. It is a unary
arithmetic operator.

**ceiling: **This is a unary operator which evaluates the integer
value closest to its argument from above.

**floor: **This is a unary operator which evaluates the integer value
closest to its argument from below.

**round: **This is a unary operator which evaluates the integer value
closest to its argument.

**truncate: **This is a unary operator which removes the fractional
part of its argument.

**sqrt: **This is a unary operator which evaluates the square root
of its argument.

**cos: **This is a unary operator which evaluates the cosine of its
argument. The argument is assumed to be given in degrees.

**sin: **This is a unary operator which evaluates the sine of its
argument. The argument is assumed to be given in degrees.

**ln: **This is a unary operator which evaluates the natural logarithm
of its argument.

**log: **This is a unary operator which evaluates the base-10 logarithm
of its argument.

Before ending this article here is one more note. Although we mentioned above, perhaps implicitly, the parameter(s) (operands in PostScript terminology) of a command may create some unpleasant problems. The command (or operator in PostScript terminology) seeks its parameter(s) in the operand stack. When found they are used by the command and deleted from the operand stack. So, deliberately or by mistake, to give a command which needs parameter(s) onto the operand stack without parameter values, will cause either a complaintabout the parameter(s) which are some topmost elements of the operand stack if they are not suitable for the parameter type, or some top element(s) of the operand stack will be removed. The user must be very careful about this point.

Before the completion of this presentation we recommend to write more complicated and comprehensive programs for the users who want to proceed on PostScript. In the following articles of these series more details will be given about the PostScript language. All questions and comments are welcome for our presentations.

*Reviewed by Jorge M. Paulo and Jose Quesada*

Webpages maintained by the LinuxFocus Editor team
© Emre Demiralp LinuxFocus 1999 |