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

Chapter 9

Procedures

In most programming languages, procedures are used to group together a set of instructions into a package that can be given a name and invoked by that name. The PostScript language provides a similar mechanism, although it is not as formal as many other languages. In particular, there are no local variables or specific parameter-passing conventions. It is up to you to decide what resources the procedure will use and how it will interact with its environment.

A PostScript procedure does not have to take its “traditional” form as a parcel of instructions to be called as a sort of subroutine. In fact, procedure bodies are used in many places without having names at all. For example, an ifelse statement requires two procedure bodies among its arguments, although only one of them is used each time ifelse is invoked.

In traditional procedural programming languages, a distinction is made between a procedure and a function. A function is simply a set of instructions that returns a value or values to the caller. For example, if you wanted to compute the average of three numbers, you might use a

105

function that had three operands passed to it and returned a real number (their average). In most traditional procedural programming languages, you need to specify what kind of value will be returned by the function while you are setting up the function itself.

PostScript procedures can act as functions quite simply by leaving something behind on the operand stack when they exit. In fact, since there is no compile-time checking of your program, a procedure might return a value inadvertently. Furthermore, a PostScript procedure acting as a function can return a value of any type, which is both good and bad. Although there are explicit data types in the PostScript language, the lack of a compile cycle forces run-time type checking, which, although it does a good job of checking types, often does so a bit too late.

WHAT EXACTLY IS A PROCEDURE?

In formal PostScript language terms, a procedure body is just an executable array, which is an array of PostScript objects that has its executable flag set. There are no further requirements of a procedure from the language’s point of view. In fact, the procedure does not even have to be composed of legal language elements for you to declare it. Since PostScript is an interpreted language, it is not until you try to run the program that the procedure will be interpreted (and that you will find out if it is written reasonably).

There are several places where procedure bodies are often found (or are required).

Procedure bodies are used with operators like loop, for, forall, and filenameforall.

Procedure bodies are used in ifelse statements to provide the true and false clauses of the conditional.

Some operators—including image, kshow, forall, settransfer, and others related to these—require procedure bodies as operands.

User-defined procedures can behave just like built-in operators, and are a useful way to extend the language.

Let’s look at a typical procedure definition and its use (Example 9.1).

106

Chapter 9: PROCEDURES

Example 9.1: Typical Procedure Definition

/S { moveto show } def (some text) 100 200 S

The procedure’s name is S, and it takes three bits of data as parameters: two real numbers (the x and y locations for moveto) and a string.

There is no mention of parameters or data required on the operand stack in the typical procedure definition. It’s okay to define procedures that are dependent on the operand stack, because you have to use them, and only you must keep the contents of the stack straight. The language does not enforce it, other than by generating an error if something doesn’t work.

In order to gain a real understanding of this common procedure definition and invocation, let’s rearrange it in some interesting ways, all of which are legal and will work just fine. Example 9.2 sets forth some alternative ways to define the S procedure of Example 9.1.

Example 9.2: Alternative Ways to Define a Procedure

(S) cvn { moveto show } def { moveto show } /S exch def

currentdict /S { moveto show } put

/S [ (moveto) cvn (show) cvn ] cvx def

All of the definitions shown in Example 9.2 have exactly the same effect. They are not different procedure definitions, they are the same procedure definition, accomplished in various ways. This illustrates that procedures are not magic; they are simply a collection of instructions in an executable array.

You can associate a procedure body with a name if you like, by creating a definition in a dictionary. This can be done in various ways (including use of put as shown as the third alternative in Example 9.2), but the simplest of them is the method that just uses the def operator. The def operator is very simplistic. All it does is take two objects and make an association between them in the current dictionary. It does not help you write correct

Chapter 9: PROCEDURES

107