|
|
Static Scope of a
Procedure Name
The static scope of the name of a procedure
determines all the procedures/functions that can call the procedure. The static scope of the name of a
procedure p() in a Pascal program is defined to include: 1. The procedure p() itself; 2. All the procedures defined directly within p(); 3. The procedure within which p() is defined, say f(); 4. All the procedures defined after p() within f(),
and in turn, all the procedures defined within them either directly or
through other procedures. A more useful concept is the converse of
the static scope of the name of a procedure, which we refer to as the callability
of the procedure. Callability of a procedure determines the procedures
that it can call. A procedure in a Pascal program can
call: 1. Itself. This is a recursive call. 2. All the procedures defined directly within it. 3. All the procedures within which its definition is nested, either
directly, or through other procedures. These procedures are called its static
ancestors. The only exception is main(), which cannot be called by
any procedure. 4. All the procedures defined before it in the
program, and directly within one of its static ancestors. Admittedly, Pascal is one of the
languages with the most complex rules for procedure callability. Since Pascal
is a statically scoped language, we can determine the callability of a
procedure in a Pascal program by studying only the text of the program. What are the procedures that compute()
can call in the following Pascal program? program main
procedure read() procedure prompt()
begin {prompt} ... end {prompt} begin {read} ... end {read} procedure compute()
procedure initialize()
procedure defaults() begin {defaults} ... end {defaults}
begin {initialize} ... end {initialize} procedure transform() begin {transform} ... end {transform}
begin {compute} ... end {compute}
procedure print()
begin {print} ... end{print} begin {main} ... end {main} Answer: The procedure compute() can call
itself recursively. It can call the procedures initialize()
and transform(), since they have been defined directly within it.
However, it cannot call the procedure defaults(), since defaults()
is defined within initialize(), and not directly within compute(). It cannot call main(),
even though main() is a static ancestor of compute(). No
procedure can call main(). It can call the procedure read(),
since read is defined before compute(), and directly within main(),
which is a static ancestor of compute(). However, it cannot
call the procedure prompt() even though prompt() is define before
compute(), because prompt() is defined within read(),
and not directly within a static ancestor of compute() (in this case, main()). It cannot call the procedure print(),
since print() is defined after compute() in the program.
Procedure callability is essential for
writing large Pascal programs. In the above example, you would not be able to
correctly answer the following questions if you did not understand the
concept of procedure callability: 1. Suppose we want to introduce a new library procedure/function
into the program called threshold(), such that both prompt()
and transform() procedures should be able to call it, where should we
insert the procedure into the program? 2. Suppose we revised the program and the need arose for the
procedure read() to call defaults(). Can read() call defaults()?
If not, how do we relocate the procedure defaults() without affecting
any of the procedures that can currently call it? Can you answer these questions? Clearly, Pascal programmers must
carefully plan the structure of large programs – the placement of procedure
definitions in the program and within each other - in order to manage the
callability of procedures. Modifying the structure of a Pascal program is not
easy. This is one of the reasons why Pascal did not gain the acceptance of
the computing industry as the programming language of choice for developing
large-scale programs. Once you have answered the above
questions, consider the effect of relocating a procedure, on its referencing
environment. This further illustrates why allowing procedure definitions to
be nested in a language greatly complicates the programs written in the
language. Therefore, most current languages (e.g., C++, Java) do not permit
definitions of procedures/functions to be nested. Algorithms
to determine the Callability of a Procedure in a Pascal program: The structure of a Pascal program, in
particular, the order in which procedure definitions are nested in the
program can be graphically depicted as a tree. This tree is called the static
tree of the program. It is quite convenient to use the static tree of a
Pascal program to determine the callability of procedures in the program. Algorithm to draw
the static tree of a Pascal program: 1. Draw the main() program as the root node of the tree. 2. Identify all the procedures/functions directly defined in main().
Draw them as child nodes of main() node. 3. Repeatedly carry out step 2 for all the leaf nodes of the tree,
until there are no more nested procedures in the program. In the Pascal program presented earlier,
the procedures read(), compute() and print() are defined
directly in main(), and are its children. The procedure prompt()
is defined within read(), and is its child. The procedures initialize()
and transform() are defined within compute() and are its
children. The procedure defaults() is defined within initialize(),
and is its child. The static tree of the program is shown below.
Algorithm to
determine the callability of a procedure p() using the static tree of the
program: A procedure can call any procedure that
it can reach by: ·
climbing up zero or more
levels of the tree; - with the exception of main(),
which cannot be called by any procedure ·
and climbing down at most one level; - and only to the left of any path by which it climbed up. Let us apply this graph algorithm to the
earlier problem of determining the procedures that compute() could
call. ·
compute() can reach itself by climbing up zero levels. Therefore, it can
call itself. ·
compute() can reach initialize() and transform() by
climbing up zero levels and climbing down one level. Since no climbing up was
involved, the restriction that climbing down should be only to the left does
not apply. Therefore, compute() can call the procedures initialize()
and transform(). ·
Although compute() can
reach main() by climbing up one level, it cannot call main(). main()
is an exception to the rule. ·
compute() can reach read() by climbing up one level and climbing
down one level to the left of the path it used to climb up. Therefore,
it can call read(). However, it cannot call print(),
since, in order to reach print(), it would have to climb down to the right
of the path it used to climb up the tree. ·
compute() cannot reach prompt() or defaults() without
climbing down more than one level. Therefore, it cannot call these
procedures. The static tree of the program is shown
again below. All the paths used by compute() to determine the
procedures it can reach, and hence call are highlighted.
Test
your understanding - Instructions: In order to better understand the concept of callability of procedures in Pascal, solve problems using the accompanying problet. The problet will present you with the outline of a Pascal program, and ask you to identify all the procedures in the program that a particular procedure can call. You may solve the problems in one of two ways: 1. You may study the program and answer the problem. In order to help you read the program, the problet provides a Format menu with options such as: a. Using different colors to indicate the different levels of nesting in the program; b. Drawing boxes to delineate definitions of procedures in the program; c. Changing the amount of indentation to set off different procedure definitions in the program. 2. Alternatively, you may study the static tree of the program and answer the problem. Choose the View menu to display the static tree of the program. Follow these steps to solve each problem (See Figure below): 1. Study either the Pascal program or its static tree in the left panel. 2. Read the question posed in the top right panel. 3. Indicate your answer in the mid-right panel, and click on Check My Answer button. 4.
Study the detailed feedback provided by the problet in
the bottom right panel. If your answer is incorrect, this panel will explain
why it is incorrect. 5.
Click on Get Another Problem button to generate
another problem.
Are you ready? Click here to launch the Problet on Static Scope Of Procedure Names. |