Control Structures Any mechanism that departs from straightline

  • Slides: 24
Download presentation
Control Structures • Any mechanism that departs from straight-line execution: – transfer of control

Control Structures • Any mechanism that departs from straight-line execution: – transfer of control (closest to machine): gotos – Selection: if-statements – Multiway-selection: case statements – Unbounded iteration: while-loops – Definite iteration: for-loops – Iterations over collections – unbounded transfer of control: exceptions, backtracking

Go. To • Recall that machine language consists of basic arithmetic (add, subtract, logical

Go. To • Recall that machine language consists of basic arithmetic (add, subtract, logical and, logical or etc. ), access to memory (memory to memory, memory to register, register to memory), and branching. • Branch statements are either unconditional (go to address X) or conditional (if result of this operation is 0 then go to address X). • All you need for a universal machine: increment, decrement, branch on zero. All the rest is programmer convenience! • But convenience facilitates reasoning about program. …

Selection • • if Condition then Statement -- Pascal, Ada if (Condition) Statement --

Selection • • if Condition then Statement -- Pascal, Ada if (Condition) Statement -- C, C++ Java To avoid ambiguities, use end marker: end if, “}” To deal with alternatives, use keyword or bracketing: if Condition then Statements else Statements end if; if (Condition) { Statements } else if (Condition) { Statements} else { Statements}

Nesting if Condition then Statements end if; else Statements end if; if (Condition) {

Nesting if Condition then Statements end if; else Statements end if; if (Condition) { Statements } else { Statements }

Statement Grouping • Pascal introduces begin-end pair to mark sequence • C/C++/Java abbreviate keywords

Statement Grouping • Pascal introduces begin-end pair to mark sequence • C/C++/Java abbreviate keywords to { } • Ada dispenses with brackets for sequences, because keywords for the enclosing control structure are sufficient: • for J in 1. . N loop … end loop; – More writing => more readable • The use of grouping in C a reminder that it is an expression language • The use of grouping in C++/Java is just syntactic tradition • Another possibility (ABC, Python): make indentation significant

Short-Circuit Evaluation • If x is more than five times greater than y, compute

Short-Circuit Evaluation • If x is more than five times greater than y, compute z: • if x / y > 5 then z : = … -- but what if y is 0? • If y /= 0 and x/ y > 5 then z : = … -- but operators evaluate their arguments • Solutions: – a lazy evaluation rule for logical operators (LISP, C, etc) – a control structure with a different syntax • C 1 && C 2 • if C 1 and then C 2 then • C 1 || C 2 • if C 1 or else C 2 then does not evaluate C 2 if C 1 is false ditto does not evaluate C 2 if C 1 is true ditto

Multiway selection • The case statement is needed when there are many possibilities “at

Multiway selection • The case statement is needed when there are many possibilities “at the same logical level. ” (I. e. depending on same condition) • Can be simulated with a sequence of if-statements, but logic become obscured. case Next_Char is when ‘I’ => Val : = 1; when ‘V’ => Val : = 5; when ‘X’ => Val : = 10; when ‘C’ => Val : = 100; when ‘D’ => Val : = 500; when ‘M’ => Val : = 1000; when others => raise Illegal_Numeral; end case;

The well-structured case statement • • Action following each choice is atomic (no flow-through)

The well-structured case statement • • Action following each choice is atomic (no flow-through) There are no duplicate choices All possible choices are covered There is mechanism to specify a default outcome for choices not given explicitly. • In some languages for sake of efficiency: : Type of expression must be discrete: and enumerable set of values (floating-point numbers not acceptable)

Implementation (compiler consideration) • Finite set of possibilities: can build a table of addresses,

Implementation (compiler consideration) • Finite set of possibilities: can build a table of addresses, and • convert expression into table index: – – – compute value transform into index retrieve address of corresponding code fragment branch to code fragment and execute branch to end of case statement • All cases have the same execution cost • All choices should be static: computable at compile-time

Complications case (X + 1) is -- any integer value (discrete but large) when

Complications case (X + 1) is -- any integer value (discrete but large) when integer’first. . 0 => Put_Line (“negative”); when 1 => Put_Line (“unit”); when 3 | 5 | 7 | 11 => Put_Line (“smal prime”); when 2 | 4 | 6 | 8 | 10 => Put_Line (“small even”); when 21 => Put_Line (“the house wins”); when 12. . 20 | 22. . 99 => Put_Line (“manageable”); when others => Put_Line (“Irrelevant”); end case; • Implementation must be combination of tables and if-statements.

Indefinite loops • All loops can be expressed as while-loops (good for invariant/assertion reasoning

Indefinite loops • All loops can be expressed as while-loops (good for invariant/assertion reasoning as we will see later) • Condition is evaluated at each iteration • If condition is initially false, loop is never executed while Condition loop. . end loop; • equivalent to if Condition then while Condition loop … end loop; end if; • (provided Condition has no side-effects…)

What if we want to execute at least once? • Pascal introduces until-loop. •

What if we want to execute at least once? • Pascal introduces until-loop. • C/C++ use different syntax with while: while (Condition) { … } do { … } while (Condition) • While form is most common • Can always simulate with a boolean variable: first : = True; while (Condition or else first) loop … first : = False; end loop;

Breaking out • More common is the need for an indefinite loop that terminates

Breaking out • More common is the need for an indefinite loop that terminates in the middle of an iteration. • C/C++/Java: break • Ada : exit statement loop -- infinite loop compute_first_part; exit when got_it; compute_some_more; end loop;

Multiple exits • Within nested loops, useful to specify exit from several of them

Multiple exits • Within nested loops, useful to specify exit from several of them • Ada solution: give names to loops • Otherwise: use a counter (Modula) or use a goto. • • • Outer: while C 1 loop. . . Inner: while C 2 loop. . . Innermost: while C 3 loop. . . exit Outer when Major_Failure; exit Inner when Small_Annoyance; . . . end loop Innermost; end loop Inner; end loop Outer;

Definite loops • • Counting loops are iterators over discrete domains: for J in

Definite loops • • Counting loops are iterators over discrete domains: for J in 1. . 10 loop … for (int I = 0; I < N; I++ ). . Design issues: – – – Evaluation of bounds (only once, ever since Algol 60) Scope of loop variable Empty loops Increments other than one Backwards iteration non-numeric domains

Evaluation of bounds for J in 1. . N loop … N : =

Evaluation of bounds for J in 1. . N loop … N : = N + 1; end loop; -- terminates? • In Ada, bounds are evaluated once before iteration starts. The above always terminates (and is abominable style). • The C/C++/Java loop has hybrid semantics: for (int J = 0; J < last; J++) { … last++; -- may not terminate! }

The loop variable • Best if local to loop and treated as constant •

The loop variable • Best if local to loop and treated as constant • Avoids issue of value at termination, and value on abrupt exit • counter : integer : = 17; -- outer declaration • . . . • for counter in 1. . 10 loop • do_something; -- 1 <= counter <= 10 • end loop; • … • -- counter is still 17

Different increments • • • The universal Algol 60 form: for J from Exp

Different increments • • • The universal Algol 60 form: for J from Exp 1 to Exp 2 by Exp 3 do… Too rich for most cases. Exp 3 is most often +1, -1. What is meaning if Exp 1 > Exp 2 and Exp 3 < 0 ? In C/ C++ for (int J = Exp 1; J <= Exp 2; J = J + Exp 3) … • In Ada: for J in 1. . N loop for J in reverse 1. . N loop -- increment is +1 -- increment is -1 • Everything else can be programmed with while-loop

Non-numeric domains • Ada form generalizes to discrete types: • for M in months

Non-numeric domains • Ada form generalizes to discrete types: • for M in months loop … • Basic pattern on other data-types: • define primitive operations: first, next, more_elements: Iterator = Collection. Iterate(); // build an iterator over a collection of elements element thing = iterator. first; // define loop variable while (iterator. more_elements ()) {. . . thing = iterator. next (); // value is each successive element }

How do we know it’s right? • Pre-Conditions and Post-conditions: • {P} S {Q}

How do we know it’s right? • Pre-Conditions and Post-conditions: • {P} S {Q} means: • if Proposition P holds before executing S, • and the execution of S terminates, • then proposition Q holds afterwards. • Need to formulate pre- and post-conditions for all statement forms, and syntax-directed rules of inference. {P and C} S {P} (P and C} while C do S end loop; {P and not C} i. e. on exit from a while-loop we know the condition is false.

Efficient exponentiation function Exp (Base : Integer; Expon : Integer) return integer is N

Efficient exponentiation function Exp (Base : Integer; Expon : Integer) return integer is N : Integer : = Expon; -- to pick up successive bits of exponent Res : Integer : = 1; -- running result Pow : Integer : = Base; -- successive powers: Base ** (2 ** I) begin while N > 0 loop -- inv: Res * (Pow ** N) == Base ** Expop if N mod 2 = 1 then Res : = Res * Pow; end if; Pow : = Pow * Pow; N : = N / 2; -- y ** k == (y^2) ** (k/2). Note: 13/2 = 6 (floor op) end loop; return Res; end Exp;

Efficient exponentiation example 2 ** 13, so 2 is the base (local variable Pow)

Efficient exponentiation example 2 ** 13, so 2 is the base (local variable Pow) and 13 is the exponent (local variable N). Initial Res is 1. First time through loop, Res goes to 2, Pow goes to 4 and N goes to 6. (2**13 = 2 (2**12) = 2 (4 ** 6)) Second time, Pow goes to 16 and N goes to 3. (4**6 = 16 ** 3). Third time: Res goes to 2*16 = 32 and Pow goes to 16*16=256 and N goes to 1. Finally: Res goes to 32 * 256

Assertion-Invariant Style • Very good programming practice. Often helps you reason through difficult loops

Assertion-Invariant Style • Very good programming practice. Often helps you reason through difficult loops (e. g. if you implement dynamic programming, you will find them useful). • Can be extended to handle exceptions.

Example of Loop with Exception (What is post-condition? ) with Integer_Text_Io; use Integer_Text_Io; function

Example of Loop with Exception (What is post-condition? ) with Integer_Text_Io; use Integer_Text_Io; function Get_Data return Integer is X : Integer; begin loop begin Get (X); return X; -- if got here, input is valid, so leave loop exception when others => Put_Line (“input must be integer, try again”); -- will restart loop to wait for a good input end; end loop; end;