A key feature of computer programs is decision making, where the program selects a result from among a list of alternatives. The PASCAL statements that support such decision making are collectively called selection structures and include the IF..THEN..ELSE and CASE statements. We will later see that the CASE statement is not in vogue (i.e., isn't used much) because it is harder to read clearly than an IF statement.
Computer program design is also facilitated by the use of program structures called loops that cause the block of statements within the loop to repeat or iterate. The latter term gives rise to the concept of iteration structures, which in PASCAL include the FOR, WHILE, and REPEAT statements.
This section is organized as follows:
In Section 4.1, we discuss the basic justification and concepts associated with iteration and selection structures, with examples of modularity in the block-IF statement. We then discuss usage of the IF and CASE statements (Section 4.2). An overview of iteration structures is given in Section 4.3, with usage of the WHILE, FOR, and REPEAT statements discussed in Section 4.4. The final topic of this section is the use of variable loop limits, which allows you to "customize" a loop with limit values that are passed into a procedure through its argument list.
Definition. A logical operator is an operation that inputs one or more values equal to zero or one, and outputs a zero (i.e., logical false) or a one (i.e., logical true).
Definition. A relational operator is an operation that inputs one or more numeric or alphabetical values and compares them to a prespecified criterion (e.g., is x greater than 3?). The result of a relational operator is a zero, if the test that the operator implements fails, and a one if the test succeeds.
Definition. A logical predicate is comprised of one or more logical or relational operations, and produces a zero or one as a result.
Definition. A Boolean value is a one or a zero.
Definition. The logical operators NOT(x), AND(x,y), and OR(x,y) are defined as follows, where x and y) are Boolean values:
NOT(x) x=0 x=1 --------+----------+ | 1 0 | +----------+ AND(x,y) x=0 x=1 --------+----------+ y=0 | 0 0 | | | y=1 | 0 1 | +----------+ OR(x,y) x=0 x=1 --------+----------+ y=0 | 0 1 | | | y=1 | 1 1 | +----------+
Definition. The relational operators are defined as:
NAME SYMBOL MEANING --------------- ---------- ------------------------------------- greater-than x > y "x" is greater than "y" greater-equal x >= y "x" is greater than or equal to "y" equals x == y "x" equals "y" not-equals x <> y "x" does not equal "y" less-equal x <= y "x" is less than or equal to "y" less-than x < y "x" is less than "y"
Observation. As we mentioned in Section 3, various attempts have been made to render computer languages more like English. One of the key constructs in this effort is the IF..THEN..ELSE statement, which is structured as follows:
IF logical-predicate THEN -- statements to execute if the predicate evaluates to true -- ELSE -- statements to execute if the predicate evaluates to false -- ENDIFExample. Suppose your program has a flag (a logical or Boolean decision variable) that causes statements to be printed to your computer monitor. For example:
IF flag THEN WRITELN('Flag is true') ELSE WRITELN('Flag is false') ENDIF
Remark. PASCAL facilitates decisions among multiple alternatives via the BLOCK-IF statement, which is comprised of multiple IF..THEN..ELSE statements that are chained together, as follows:
IF predicate-1 THEN -- statements to execute if predicate-1 evaluates to true -- ELSEIF predicate-2 THEN -- statements to execute if predicate-2 evaluates to true -- ELSEIF ... ELSEIF predicate-n THEN -- statements to execute if predicate-n evaluates to true -- ELSE -- statements to execute if the preceding predicates all evaluate to false -- ENDIF
In the 1970s, programming language designers were looking for simpler ways to write statements that were previously involved expressions. Since the programmers made more errors on complex statements, it seemed reasonable to attempt to distill the BLOCK-IF into a more concise representation. In PASCAL, this representation is called the CASE statement. Instead of relational operators, the CASE statement simply specifies possible values for a variable, together with statements to be executed if that variable has a given value. For example, consider the following CASE statement (written in pseudocode) for a academic grade evaluation:
CASE OF grade: 'A': WRITELN('Excellent work!'); 'B': WRITELN('You did well...'); 'C': WRITELN('Average performance.'); 'D': WRITELN('Needs some improvement...'); 'E': WRITELN('Trouble ahead!'); END-CASECertainly this simple instance of the CASE statement is easier to read than the corresponding BLOCK-IF statement:
IF grade == 'A' THEN WRITELN('Excellent work!') ELSEIF grade == 'B' THEN WRITELN('You did well...'); ELSEIF grade == 'C' THEN WRITELN('Average performance.'); ELSEIF grade == 'D' THEN WRITELN('Needs some improvement...'); ELSEIF grade == 'E' THEN WRITELN('Trouble ahead!'); ENDIFThe problem with CASE statements occurs not when the statement blocks are small, or when there are a few alternatives. Rather, the CASE statement begins to defeat its design goal of conciseness and readability when the blocks of statements become large or when there are many alternatives. In such expressions, a given CASE statement may span several pages or more. When you are trying to debug such statements, it becomes very difficult to remember where you are in the statement, and one tends to feel lost. As a result, we prefer to use only IF or BLOCK-IF statements for decision structures.
IF..THEN..ELSE
statement:
Purpose: The IF statement provides a mechanism for decision based on a logical predicate.
Syntax: IF predicate THEN
actions-if-predicate-is-true
, where
ELSE actions-if-predicate-is-false ;
actions-if-predicate-is-true
are one
or more PASCAL statements
actions-if-predicate-is-false
are one
or more PASCAL statements
Example:
IF ((score > 90) AND (score <= 100)) THEN grade := 'A' ELSE WRITELN('You did not get an A') ;
Notes: When single statements are used in an IF statement block, one must take care not to put a semicolon after the statement that follows the IF...ELSE block. Otherwise, the PASCAL compiler will infer that the IF statement should be terminated at the semicolon. So, the semicolon goes after the ELSE predicates, as shown above. When the IF statement is used to execute large blocks of compound statements, then the BEGIN..END construct should be used to delimit those statement blocks.
IF..THEN..ELSEIF..THEN..ELSE
(Block-IF) statement:
Purpose: The Block-IF statement provides a mechanism for decision based on multiple logical predicates. This can be useful for grouping data items into prespecified categories.
Syntax: IF predicate1 THEN
actions-if-predicate1-is-true
, where
ELSEIF predicate2 THEN
actions-if-predicate2-is-true
:
ELSEIF predicateN THEN
actions-if-predicateN-is-true
ELSE actions-if-predicates-are-false ;
actions-if-predicate-is-true
are one
or more PASCAL statements
actions-if-predicate-is-false
are one
or more PASCAL statements
Example:
IF ((score > 90) AND (score <= 100)) THEN grade := 'A' ELSEIF ((score > 80) AND (score <= 90)) THEN grade := 'B' ELSEIF ((score > 70) AND (score <= 80)) THEN grade := 'C' ELSEIF ((score > 60) AND (score <= 70)) THEN grade := 'D' ELSE WRITELN('You got an E') ;
PASCAL also supports nested decision structures, in which an IF statement contains other IF statements in its list of executable statements. This allows the programmer to specify decisions based on concepts or criteria that are hierarchically structured.
Definition. A loop is a section of code that repeats itself.
Definition. A loop index or loop counter is an integer variable that is used to keep track of how many times a loop has executed.
Definition. A loop limit is a variable or constant that is integer-valued, which determines the number of times a loop will execute, or a maximum value of the loop index to be reached at loop termination.
Definition. A loop increment is the step size for incrementing the loop counter.
Example. The following pseudocode fragment
WRITELN('before loop starts') FOR i = 1 TO 5 DO: WRITELN('iteration number ',i) ENDFOR WRITELN('after loop ends')generates this output on the computer monitor:
before loop starts iteration number 1 iteration number 2 iteration number 3 iteration number 4 iteration number 5 after loop endsHere, the loop index is the variable "i", and the loop limits are one and five, with an implicit loop increment of one.
Definition. In certain kinds of loops (WHILE..DO and REPEAT), there is no loop index, but a loop predicate that is a logical predicate (defined in Section 4.1). When the predicate evaluates to false, the loop terminates.
Example. Let's rewrite the preceding FOR loop as a loop with a predicate. The following pseudocode fragment
WRITELN('before loop starts') i := 0 ## Initialize counter variable WHILE (i <= 5) DO: ## Loop with predicate in () i := i + 1 ## Increment counter variable WRITELN('iteration number ',i) ENDFOR WRITELN('after loop ends')generates the same output as before, namely,
before loop starts iteration number 1 iteration number 2 iteration number 3 iteration number 4 iteration number 5 after loop endsHere, the loop predicate is the relational test "
i <= 5
", which causes the loop to
terminate after i is incremented to six.
Answer. First observe that the WHILE..DO loop is more tedious to write and understand than the FOR loop, because the WHILE loop requires that the predicate variable (in this case, "i") be changed within the loop. In contrast, the FOR loop increments and keeps track of i internally (i.e., in a manner transparent to the programmer).
Second, the WHILE..DO construct only executes the loop contents while the predicate is satisfied. As soon as the predicate evaluates to false, the loop terminates.
Example. Consider a situation where one adds characters to a word to form a prespecified test word, as in the following pseudocode:
WRITELN('before loop starts') string := 'ADDIS A' ## Initialize test variable test := 'ADDIS ABABA' ## Test value to stop loop on WHILE string <> test DO: WRITELN('string = ',string) ## Show string before it's modified string := string || 'AB' ## Append "AB" to the string WRITELN('string = ',string) ## Show string after it's modified ENDFOR WRITELN('after loop ends') WRITELN('string = ',string) ## Write final value of stringwhich forms this output:
before loop starts ADDIS A ADDIS ABA ADDIS ABA after loop ends ADDIS ABABA
Answer. The WHILE loop iterates until the predicate is satisfied. In the above example, the predicate tells the runtime module to stop executing the loop when string equals "ADDIS ABABA". That means that as soon as the string equals the test value of ADDIS ABABA, then the loop terminates. Thus, the value of the completed string never gets written from inside the loop. Hence, the value of string must be written outside the loop. Since flow of control is sequential, this means that the WRITELN statement must be placed at the end of the loop.
Example. Contrast the following pseudocode fragment with the WHILE loop example that we just discussed:
WRITELN('before loop starts') string := 'ADDIS A' ## Initialize test variable test := 'ADDIS ABABA' ## Test value to stop loop on REPEAT ## Start loop WRITELN('string = ',string) ## Show string before it's modified string := string || 'AB' ## Append "AB" to the string WRITELN('string = ',string) ## Show string after it's modified UNTIL (string == test) ## Test for loop termination WRITELN('after loop ends') WRITELN('string = ',string) ## Write final value of stringwhich forms this output:
before loop starts ADDIS A ADDIS ABA ADDIS ABA after loop ends ADDIS ABABANote that the output is the same, but the loop structure is different, because the predicate is expressed using the opposite relational operator (i.e., "==" instead of "<>"). This is due to the semantics or meaning of the statement
WHILE (x is true) DO <statements>which has the same meaning as
REPEAT <statements> UNTIL (x is false)Thus, a WHILE loop can be approximated by a REPEAT loop merely by moving the predicate to the end of the loop and negating the logic of the predicate.
We next examine the PASCAL syntax of the FOR, WHILE, and REPEAT loops.
FOR
loop:
Purpose: Repeat statements within the loop while the loop index is incremented within specified bounds.
Syntax: FOR loop-index := initial-value TO
final-value DO
, where
statements ;
loop-index
is the counter to be
incremented
initial-value
is the beginning value
of the loop index
final-value
is the ending value
of the loop index
Example:
n := 5 FOR i := 1 to n DO WRITELN('i = ', i) ;
Notes: In the preceding example, we have used a parameterized loop, whereby the variable n contains the loop index' final value. This technique is useful in software engineering and will be discussed in greater detail in Section 4.5.
WHILE..DO
loop:
Purpose: The WHILE loop is also called a conditional loop, since it terminates based on a condition encoded in a logical predicate.
Syntax: WHILE predicate DO
statements ;
, where
predicate
is the controlling
condition.
Example:
x := 10 WHILE x > 5 DO BEGIN x := x - 2 WRITELN('x = ', x) END;
REPEAT..UNTIL
loop:
Purpose: The REPEAT loop is another example of a conditional loop.
Syntax: REPEAT statements
UNTIL predicate;
, where
predicate
is the controlling
condition.
Example: (approximation of previous WHILE loop)
x := 10 REPEAT BEGIN x := x - 2 ; WRITELN('x = ', x); END; UNTIL x <= 5 ;
In the example of the FOR loop, we saw how a variable could be used to specify a loop index. We next elaborate this technique, and show how it can be used to encapsulate a loop in a procedural construct.
PROGRAM TestLoop; {Program specification} VAR x,y: integer; {Declare variables x,y as integer} PROCEDURE Loop(x,y:integer); {Function specification: inputs} VAR i: integer; {Declare loop index} BEGIN {Function begins here} FOR i := x TO y DO {Loop specification} WRITELN('i = ', i); {Loop contents or body} END; {Function ends here} BEGIN {Program begins here} x := 4; {Assign starting loop index value} y := 7; {Assign ending loop index value} Loop(x,y); {Call to procedure "Loop"} END. {Program ends here}In the preceding PASCAL code, note that the VAR statement specifies a variable of integer datatype. In this case, the variables x and y are specified as integers. Additionally, the
WRITELN
statement outputs the value of i to the screen, as follows:
i = 4 i = 5 i = 6 i = 7per the preceding discussion.
Variable loop limits are especially useful when performing tasks in image and signal processing or database manipulations, where the data structure size is parameterized, i.e., can be changed by changing a value encoded in a variable. For example, one often processes images of varying size, cuts or pastes parts of images, etc. By having variable loop indices, you do not need to recode each loop explicity with different limits for different sized images. Once you know how large the image is, you can merely pass the loop limits through the procedure call's argument list and constrain processing to any size image or neighborhood of an image that is within the prespecified array limits.
Good software engineering practice dictates that all loop limits be specified in terms of variables if the loop is to be called from within a procedure, and the loop limits are at any time expected to be flexible. Rather than having to recode a program with variable loop limits (which can be a difficult task), variable limits that are already implemented make the task of resizing a loop much easier. As noted previously, this facilitates modularity and portability of PASCAL code, and makes debugging much easier.
This concludes our overview of selection and iteration structures
in PASCAL.
We next discuss PASCAL files, file I/O, and arrays.
Copyright © 1997 by Mark S. Schmalz
All rights reserved except printing by UF students registered for this class.