Control Structures Programs utilize 4 basic control structures
Control Structures • Programs utilize 4 basic control structures – – Sequential (default, no special instructions required) Selection Repetition Unconditional Branching • GO TO statement (including break, continue) • subroutine calls (those that involve parameter passing and a return location) • For purposes of local scope and easier syntax, we can add blocks, or compound statements – – ALGOL 60 - first language to introduce blocks Pascal-like languages (including ALGOL) used begin-end C-like languages use { } Lisp uses ( )
Selection Statements • Gives a program the ability to choose which instruction(s) to next execute based on conditions • Types: – – 1 -Way selection (if statement) 2 -Way selection (if-else statement) 3 -Way selection (FORTRAN’s early if statement) multiple selection (or n-way selection, switch/case) • Design issues: – what is the form and type of expression that controls the selection? (C allows 0/non-0, Java/C# allow only boolean) – how are clauses specified if at all? – if nesting is allowed, how is it specified and implemented?
One-way Selection • One-way: if without else – if condition is true then execute next statement, otherwise skip over it • originally, FORTRAN did not have a true IF statement, but when introduced, it was a One-Way selection only (no Else clause, no nesting) • if then clause has more than 1, instruction, we alter the semantics of the statement, to what is in essence an “else-goto” rather than, an “if-then” If (. NOT. Condition) GOTO 20 I=1 J=2 20 Continue • nearly every language since has allowed two-way selections
Two-Way Selection • ALGOL 60 introduced the first true two-way selection – terms “then-clause” & “else-clause” introduced – clauses are expected to be a single instruction to easily detect the end of each clause, otherwise, must use blocks – ALGOL 60 allowed more than one entry into the twoway selection clauses! – in languages where the “then” is omitted, the condition must be placed in ( ) to denote its end
Three-Way Selection • Only available in FORTRAN – IF (expression) N 1, N 2, N 3 – Meaning: if expression < 0 then goto N 1, if = 0 goto N 2, if > 0 goto N 3 • This was easy to translate into machine language code – – Evaluate expression JL N 1 JE N 2 JG N 3 • This was FORTRAN I-IVs only IF statement!
Blocks • ALGOL introduced the block structure – in part this allowed multiple instructions for the if/else clause – it also can be used to show where an if clause ends to permit an else (this is what FORTRAN didn’t have) – blocks require delimiters – begin. . end, { }, ( ) (Python uses indentation), here we see an example in ALGOL • if (Boolean expression) then begin statement 1; . . . statement n end; – Ada and FORTRAN 95 have explicit end-type statements (e. g. , endif, endfor)
Nesting • Nested If-Then-Else statements can lead to ambiguity if there is a miss-match between conditions and else clauses • In Perl, Ruby, ALGOL 60, FORTRAN 77/90/95, Modula-2 and Ada, all clauses must have explicit end statements (even if there is only a single statement in the clause) – this avoids the dangling or mismatched else problem • In C/C++/Java/C# and Pascal, a compiler rule matches mismatched elses with the last unmatched condition – in order to the change this matching behavior, you must use blocks
Dangling Else Example Which condition does the else go with? Is result = 1 if sum != 0 or if sum = = 0 and count != 0? Example in C if(sum = = 0) if (count = = 0) result = 0; else result = 1; if sum = = 0 then if count = = 0 then result = 0 else result = 1 end if sum = = 0 then if count = = 0 then result = 0 end else result = 1 end
Multiple Selection Constructs • ALGOL-W introduced the case statement – Pascal, Modula and Ada, FORTRAN 90/95 all use this – C/C++/Java/C# use the switch statement • implementation of the switch differs in that execution continues to test each condition even after a previous action executed – unless you use break statements • to fix this oddity, in C# you must end each case with a break or goto • C# also permits string comparisons – Lisp uses the COND statement which can utilize any form of condition, not just comparing an ordinal to a list of values – all of these allow for a default if none of the cases is selected • default in C-languages, else in Pascal, when others in Ada • Perl/Python don’t have a multi-selection statement at all!
Nested If-Else Constructs • Cond in Lisp is really a nested if-then-else function – Lisp also provides a “default” by using T as the final condition • Other languages have provided a specific if-then-else nested construct for convenience – Ada uses elsif if the intention is to do “else if” so that you do not have to explicitly end each if statement with an end if – Python, among other languages uses elif so that you don’t have to continue to indent Ada without elsif: if Count < 10 then Bag 1 : = True; else if Count < 100 then Bag 2 : = True; Ada with elsif: else if Count < 10 then Bag 1 : = True; if Count < 1000 then elsif Count < 100 then Bag 2 : = True; Bag 3 : = True; elsif Count < 1000 then Bag 3 : = True; end if;
Repetition Statements • Every language has included some form of repetition, either counter-controlled (early FORTRAN), logicallycontrolled, iterator-based or some combination • Issues: – – how is repetition controlled? is testing before or after the loop body? (pre vs. post test) where should the control mechanism appear in the loop? for counter-controlled loops • what are legal types and the scope of the loop control variable? • what happens to the variable when the loop terminates? • can the loop’s controlling variables (terminating value, stepsize) be altered during execution? • are the loop controlling variables (terminating value, step-size) evaluated once (before executing the loop) or after each iteration? • what are legal step-sizes (for counter-controlled loops)
FORTRAN’s DO statement • DO label variable = initial, terminal [, step] – example: Do 10 K = 1, 10 – FORTRAN I – IV: a posttest loop, stepsize defaults to 1 – label is a line number that indicates the last instruction in the loop body • this line usually has one instruction called CONTINUE as in – 10 CONTINUE – FORTRAN 77, 90 and 95: pretest loop • Integers (literals or variables) only for initial, terminal, step – the values of initial, terminal and step are computed prior to loop execution so that the number of loop iterations is computed at that time and static • if a variable changes values during loop execution, it has no impact on the number of loop iterations
Example DO 10 I = J, K * 10, L K=K+1 L=L+2 10 CONTINUE If J = 1, K = 5, L = 2, the loop would iterate 25 times in spite of K and L changing in the loop body initvalue = J terminalvalue = K * 10 stepvalue = L iterationcount = max(int((K*10 – J) / L), 1) In FORTRAN I-IV, this is a post-test loop so it must iterate at least 1 time, in later FORTRANs, this would become 0
ALGOL For Loop • ALGOL 60 introduced an extremely flexible for loop as a response to FORTRAN’s primitive and restrictive Do – the programmer controls the number of iterations by • a counter controlled mechanism like FORTRAN’s DO but where the step size and terminating value could change during iterations • enumerating a list of values to iterate through • using a logical statement to control termination • or any combination thereof • Basic form: – for <var> : = <list>{, <list>} <list> <expr> | <expr> while <boolean> | <expr> step <expr> until <expr> do <stmt> – <expr> can be a literal value or arithmetic expr
Examples • for count : =1, 2, 3, 4, 5, 6, 7 do list[count]: =0 • for count: = 1 step 1 until 7 do list[count]: =0 • for count: =1, count+1 while (count <=7) do list[count]: =0 • for I : = 1, 4, 13, step 5 until 23, 3*I while I < 300, 8, -4 do … – the values for I iterate through: 1, 4, 13, 18, 23, 69, 207, 8, -4
Other Languages For Loops • COBOL – Perform <expr> Times <statements> End-Perform – Perform Varying <var> From <expr> By <expr> Until <expr> <statements> End-Perform • PL/I – DO <var> = <start> TO <stop> {BY <stepsize>}; <statements> END; – <start>, <stop> and <stepsize> can be int or float values – like FORTRAN though, the values are only evaluated once before the loop starts – can have multiple lists of <start> TO <stop> values • DO I = 1 TO 10, 20 to 30, 50 TO 100; … • Ada – for <var> in [reverse] <range> loop. . . end loop – <range> is a subrange as in 1. . 10 (the values can be ints or enumerated types)
Continued • Pascal – for <var> : = <init> (to | downto) <final> do – <var>, <init>, <final> are any ordinal type but are evaluated prior to the start of the loop – step size is fixed as 1 or -1 (-1 for downto) • Common Lisp: (do ((<var> <init> <step>)) ((<endtest> {. <result>})) <statements>) – <init>, <step>, <endtest> and <result> can be functions or atoms – <result> if specified is returned when the loop exits as this function’s return value (otherwise the last <statements>’s result is returned) – <var>’s scope is only for the loop itself – Common Lisp also has the DOTIMES loop for a true counting loop
Iterator Loops • Iterate once for each item in the specified list (or data structure) – Algol’s for loop has the capability of iterating over a list, but the list must be explicitly enumerated – Python: for <var> in <range>: • <range> will be a tuple or range(value [, value]) • note that Python’s for loop can also be a counting loop by using the range function as in for x in range(0, 10, 2) which iterates over 0, 2, 4, 6, 8, 10 – C# has a foreach statement which can iterate across array elements – Java 5. 0’s for loop has been enhanced to work on objects of type Iterable – Common Lisp has a dolist statement much like C#’s foreach
Logically Controlled Loops • Issues – pretest vs. posttest (test condition before entry or after execution? ) • pre-test can block entry to loop body, post-test must execute body at least once • in C, C++ and Java, the post-test loop has the same semantics as the pre-test loop: repeat while the condition is true • in Pascal, the semantics are reversed: repeat until condition becomes false • C-like languages, Pascal, Modula-2 have both pretest and posttest loops • Ada only has posttest • FORTRAN has no logically controlled loop (even FORTRAN 95) – is this type of statement separate from the counter-controlled loop?
Exiting Loops • Should exiting a loop only be permitted at the end when the test returns false or can premature exiting (and returning) be permitted? – Ada has a conditional-less loop (infinite loop) which requires a GOTO to break out of • loop. . . end loop – C/C++/Java/C# and Modula-2 have break, continue, exit (all forms of GOTO statements) • Java has break and exit but not continue • Multiple exits harm readability – exception handling is a more reliable and readable way to go – COBOL has an odd form of exception handling in loops • Perform <paragraph> Thru <paragraph> • both paragraphs are executed, if an error arises in the first paragraph, control exits to the second paragraph
Problems with Unconditional Branching • Can make programs unreadable, harms readability and reliability making maintenance more challenging • The GO TO statement is too primitive – “it is an invitation to make a mess of one’s program” – GOTO statements are required in assembly/machine code because they do not have the high-level language constructs, but the high level languages should offer these constructs and let the compiler do the work • Most languages have some form of GOTO statement – Modula-2, Bliss, CLU, Euclid, Gypsy do not! – Java has a GOTO, but it hasn’t been implemented (yet) • What we learned from FORTRAN was that the GOTO is not needed if you have good control statements
GOTO Labels • Used in ALGOL 60, C, FORTRAN and Ada as locations for GOTO commands – in Ada, <<label>> – in FORTRAN and Pascal, unsigned integer constant (20, 100, etc. . . ) • in Pascal, labels must be declared as if they were variables (but cannot be modified or passed as a parameter) – in C, ALGOL 60, any legal identifier • Most languages restrict the use of unconditional branches with respect to which label can be reached – in Pascal, the scope of the label is the same as the scope of a variable and the target of the GOTO must be • within the control statement that includes the GOTO or • a statement in the same group that contains the GOTO or • in a statement in an enclosing subprogram scope
- Slides: 22