• Keine Ergebnisse gefunden

When to Use Outer Variables

The last one or more parameters in a parameter list may be qualified with "REPEAT ABLE"

6.5. When to Use Outer Variables

stack, stackDepth, and timeToQuit are the outer variables in Example 6.4-1. They could all have been declared in the initial procedure instead, but then they would have had to be passed as parameters to all the procedures that manipulate them. In the case of stack and stackDepth,

BEGIN "rpn"

BOOLEAN timeToQuit;

*

An outer variable; true if "Q"

*

command seen

STRING stack;

*

The stack of numbers.

INTEGER stackDepth;

*

How many numbers are on the stack

*

now.

STRING PROCEDURE getCommand (MODIFIES STRING s);

*

Return the next thing on the command line. If i t is

*

"Q" or the end of the line, return the null string.

*

If i t is illegal, write an error message and return

*

the null string.

*

Remove the string read from s.

BEGIN

INTEGER Chi STRING t,ui

WHILE first(s) = , , OR first(s) = first (tab) DO cRead(s);

# Remove initial blanks and tabs, if any t := 'It';

WHILE s NEQ "" AND

IF t IF t

(first(s) NEQ' , AND first(s) NEQ first(tab» DO cWrite(t,cRead(s»;

*

Add the next character to the

*

result string

"Q" THENB timeToQuit

:=

TRUE; RETURN ("") END;'

"+,, OR t

=

"S" OR t

= ""

THEN RETURN(t)i

Example 6.4-1. Use of Outer Variables (continued)

:# If i t isn't "Q", "S", "+", or nothing, then it must be

~ :# an integer or illegal.

j u := t;

WHILE u DOB

ch := cRead(u);

:# Take advantage of the assumption that the digit :# characters are contiguous (see the "MAINSAIL :# Language Manual") .

IF ch < '0' OR ch

>

'9' THENB

write(logFile,"Illegal command ",t,eol);

RETURN (nn) END END;

RETURN(t); :# It was an integer END;

PROCEDURE push (STRING s);

:# Add the integer in s to the top of the stack. The :# integers are separated by the space character.

BEGIN

cWrite(stack,' ' ) i stack "= stack & Si

stackDepth

:=

stackDepth

+

1;

END;

STRING PROCEDURE stackTop (OPTIONAL BOOLEAN doNotPop) ; :# Unless doNotPop is true, remove the top item from the :# stack.

BEGIN

INTEGER Chi STRING Si

Example 6.4-1. Use of Outer Variables (continued)

IF stackDepth

<

1 THENB

write (logFile, "Stack empty."); RETURN ("") END;

S

. .= "".

,

DOB ch := rcRead(stack);

IF ch NEQ ' , THEN rcWrite(s,ch);

END UNTIL ch

= , ';

stackDepth := stackDepth - 1;

IF doNotPop THEN push(s); # Put i t back onto the stack RETURN (s) ;

END;

STRING PROCEDURE stringAdd (STRING s,t);

# The strings sand t represent integers. Return the

# string that represents their sum.

BEGIN

INTEGER i , j ; STRING u;

# Take the easy way out by using "read" and "write".

# Note that if i, j, or their sum is larger than 32,767,

# this procedure may not work.

read(s,i); read(t,j); u := ""; write(u,i + j);

RETURN(u);

END;

Example 6.4-1. Use of Outer Variables (continued)

PROCEDURE processCommand (STRING s);

-# If s

=

"+", pop the top two items from the stack, add -# them, then push the result onto the stack. If s is -# an integer, push i t onto the stack.

BEGIN

STRING t,u;

IF s

=

"S" THEN write(logFile,"Stack:",stack,eol) EF s

= "+,,

THENB

IF stackDepth < 2 THEN

write(logFile,"Cannot add; stack has only", stackDepth," items." & eol)

EB t := stackTop; u := stackTop;

push(stringAdd(t,u» END END EL push(s);

END;

INITIAL PROCEDURE;

BEGIN

STRING s,t;

timeToQuit :== FALSE; -# Haven't seen "Q" yet

stack

:= "";

stackDepth

:=

0; -# No numbers on stack yet DOB write(logFile,"CALC: "); read(cmdFile,s);

END;

s := CVU(S)i -# Convert to upper case so as not to i have to distinguish "Q"I"q", "S"I"s"

DOB t :== getCommand(s); -# getCommand returns the null -# string at end of line or if -# command "Q" seen

IF t NEQ I'"~ THEN processCommand(t);

END UNTIL t == "";

write(logFile,stackTop(TRUE),eol) ; END UNTIL timeToQuit;

END "rpn"

Example 6.4-1. Use of Outer Variables (end)

this would be inconvenient, since nearly all the procedures manipulate them, and the same two

*rpn<eol>

Illegal command WFKPE 66

Example 6.4-2. Execution of RPN

Some philosophers of computer programming consider that is better, when possible, to use local variables and pass parameters instead of sharing data among procedures using outer variables. They think this makes it more obvious what data are consumed and produced by each procedure, since all of the relevant input values and output variables appear in the procedure call itself. Others feel that long lists of parameters passed over and over to different procedures clutter the code and make programs difficult to read, and try to pass as much information as possible in outer variables. The examples in this tutorial try to steer a middle course; data shared among many procedures are represented in outer variables, whereas information used primarily in a small number of procedures is passed around through parameters.

Under these principles, timeToQuit in Example 6.4-1 might well have been declared in the initial procedure and set by getCommand, since getCommand and the initial procedure are the

only two procedures in which the variable timeToQuit appears. getCommand's procedure header would have been changed to:

STRING PROCEDURE getCommand (MODIFIES STRING s;

PRODUCES BOOLEAN timeToQuit) ; and its call in the initial procedure to:

getCommand(s,timeToQuit)

However, timeToQuit was made an outer variable with the idea that the program might someday be expanded to have more conditions that required termination, and so procedures other than getCommand might set timeToQuit. timeToQuit can also be viewed as a property of the program as a whole, and therefore worthy of appearing in the declarations at the beginning of the module, where a human reader trying to understand the program often starts.

6.6. Exercises

Exercise 6-1.

Rewrite the procedure stringAdd in Example 6.4-1 to handle numbers larger than MAINSAIL's maximum integer by doing the arithmetic on strings yourself instead of calling "read" and "write". You need handle only nonnegative numbers.

Exercise 6·2.

Write a more sophisticated Reverse Polish Notation calculator than that of Example 6.4-1. Support negative and nonnegative integers of any length, subtraction,

multiplication, and division as well as addition. Also provide a way to clear the stack (I.e., remove all the numbers from the stack).

7. Even More on Procedures; the Done and Continue