Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Reid G.C.Thinking in PostScript.1990.pdf
Скачиваний:
17
Добавлен:
23.08.2013
Размер:
846.44 Кб
Скачать

Chapter 6

Trusting the Stack

Most beginning PostScript programmers don’t trust the operand stack. It seems like just a vehicle for transporting data to their procedures, and the sooner the data can be retrieved from the stack and put safely into a variable, the happier the programmer is.

There is a vague truth to this feeling, but it has only to do with the programmer, and not the PostScript language itself. It is a bit more difficult to think like a stack-based interpreter, so you can get confused about what is on the stack, how it got there, and what you should do with it, and this confusion can lead to bugs and lost data. However, since you cannot avoid the operand stack when writing PostScript programs, it is best just to master it, rather than to mistrust it.

67

SAFETY OF DATA ON THE STACK

In truth, the safest place for a piece of data is on the operand stack, with a few small caveats.

If your program has bugs, you may inadvertently remove something from the operand stack that you needed, or leave something extra that will cause some later operation to trip over it. Sometimes these stack alignment programs persist for a long time, unless you consistently test all the paths through your program.

Stack-based manipulations of more than a few operations or more than a few operands can be tricky to read and maintain, leading to the bugs just mentioned.

If you transfer control temporarily to some other program, as you might do with an embedded illustration, for example, you should not be surprised if something you left on the operand stack is no longer there.

In general, the cleanest, fastest and best programs are those that make judicious use of the operand stack. As a rough rule of thumb, in designing a PostScript program you should spend 65 percent of your time thinking about the order of operands on the stack, whether or not you should divide all of your coordinate numbers by 1,000 before sending them to the interpreter, and whether you can get away without sending the X coordinate every time you plot a vertical line. You should spend 20 percent of your time adjusting the procedures you have defined to match the decisions you have made about operand order and use. (The remaining 15 percent is for debugging and getting distracted.)

Of course, these principles of careful use of the operand stack are derived primarily from printer drivers, which are inherently batch programs. If you are writing an interactive application in PostScript, or if you are writing a utility program that is entirely self-contained, you may have different goals—but the basic ideas still apply. The data must be on the operand stack in order for any PostScript operator to use it, so you might as well take advantage of that premise and try not to take things off the stack and put them on too many times unnecessarily.

68

Chapter 6: TRUSTING THE STACK

The name of this chapter is the key: trust the operand stack. You should not simply follow a recipe that says always to use the stack or always to use variable names. Use the operand stack wisely, use it when speed is important, and use it because it is already there. Use it because you have mastered it and have learned its strengths and weaknesses and because you have to use it anyway.

Remember that the operand stack is used by every PostScript operator and procedure as the way to pass data and operands. The more cleanly your program supports this natural interface, the faster and more efficient it will be.

WHERE ARE THE DATA GOING?

One of the important things to consider when you’re designing a PostScript program is what you’re using the stack for at any given moment. Are you passing parameters to a function? Is the information on the stack raw data? Will the information be used once or many times? If you only need the data once, it is best to arrange it in such a way that you can use the data directly from the operand stack and never think about it again.

A common approach to dealing with data on the operand stack is to store the data under some name in a dictionary, rather than leaving the values on the operand stack. This has a few advantages.

The data can be recalled onto the stack many times.

Debugging can be easier with named data.

Storing the data helps to minimize nasty stack manipulations.

The first few times you try to read or write PostScript programs, it may be difficult to understand what is going on in a statement like the one in Example 6.1. What is exch doing exactly where you would expect to see the value part of the definition?

As you know, the def operator requires its key and value in a particular order on the stack. If the value—the object you want to store—got put on the operand stack before you had a chance to put the key—the name under which you store that value—on the stack, then you would have them in the wrong order for def. In this case, you need to call exch to get them in

Chapter 6: TRUSTING THE STACK

69

the right order. It gets just slightly more confusing when the expression is buried inside a procedure somewhere. You can’t see the value at all in that case, because it isn’t on the stack yet. It won’t be until you run the program and some operation produces the value as it executes.

If you call a procedure with many pieces of data on the operand stack as arguments, it can be a little bit tricky to get them stored into a dictionary. The typical trick is to associate keys with them and to execute def. A small amount of operand stack manipulation is required. Since the operands are in stack order, they need to be taken from the stack in the opposite order (see Example 6.1).

Example 6.1: Using exch def in a Procedure

/proc

% A B C proc -

{ %def

 

/C exch def

 

/B exch def

 

/A exch def

 

} def

 

(a) (b) (c) proc

 

Remember that the code fragment

(a) /A exch def

is equivalent to

/A (a) def

(without the exch), which is why it works. (See also Thinking Backward and Sideways in Chapter 5.)

Once you have collected the operands into the current dictionary, you simply call them by name in order to use them. Each time you supply the name in your program, it will be looked up in the current dictionary (or dictionary stack) and the value will be placed on the operand stack again.

70

Chapter 6: TRUSTING THE STACK