Presentation is loading. Please wait.

Presentation is loading. Please wait.

CSCI 330: Programming Language Concepts Instructor: Pranava K. Jha Control Flow-II: Execution Order.

Similar presentations


Presentation on theme: "CSCI 330: Programming Language Concepts Instructor: Pranava K. Jha Control Flow-II: Execution Order."— Presentation transcript:

1 CSCI 330: Programming Language Concepts Instructor: Pranava K. Jha Control Flow-II: Execution Order

2 Execution Order Sequencing: the execution of statements and evaluation of expressions is in the order in which they appear Selection: a run-time condition determines the choice among two or more statements or expressions Iteration: a statement is repeated a number of times until a run-time condition is met Procedural abstraction: subroutines that encapsulate collections of statements and can be treated as single statements Recursion: subroutines which call themselves directly or indirectly to solve a problem, where the problem is typically defined in terms of simpler versions of itself Concurrency: two or more program fragments executed in parallel, either on separate processors or interleaved on a single processor Nondeterminacy: the execution order is deliberately left unspecified, indicating that any alternative will lead to a correct result

3 Unstructured Flow Goto statements feature prominently in early imperative languages Merits and evils of gotos hotly debated throughout the late 1960s and much of the 1970s. See the following papers: 1.Edsger W. Dijkstra (March 1968), “Goto statement considered harmful,” Letter to the editor, Communications of the ACM, 11 (3): 147–148.Edsger W. Dijkstra 2.Donald E. Knuth (December 1974), ”Structured Programming with goto Statements,” ACM Computing Surveys, 6 (4): 261 - 301 Donald E. Knuth

4 Unstructured Flow Gotos are generally considered bad, but are sometimes useful for jumping out of nested loops and for coding the flow of exceptions (when a language does not support exception handling). – Ada, C# allow gotos in limited contexts. – Modula, Clu, Eiffel and Java ban them. – Fortran 90 and C++ allow them primarily for compatibility.

5 Spaghetti Code int foobar(int x, int z, int s) { void* next = &&cell0; int retVal = 0; cell0: next = (s==1) ? &&cell1 : &&cell2; goto *next; cell1: retVal = x*7; goto end; cell2: next = (s==2) ? &&cell3 : &&end; goto *next; cell3: next = (x==z) ? &&cell4 : &&end; goto *next; cell4: { printf("%i\n",x); goto end; } end: return retVal; }

6 Untangle Spaghetti Code int foobar(int x, int z, int s) { if (s==1) return x*7; else if (s==2) if (x==z) printf("%i\n",x); }

7 Structured Flow Statement sequencing Selection with “if-then-else” statements and “switch” statements Iteration with “for” and “while” loop statements Subroutine calls (including recursion) Alternatives to gotos – Mid-loop exit and continue – Early returns from subroutines – Multilevel returns – Errors and exceptions – Continuation

8 Sequencing – specifies a linear ordering on statements one statement follows another – very imperative, Von-Neumann-style

9 Sequencing A list of statements in a program text is executed in top-down order. A compound statement is a delimited list of statements. A compound statement is called a block when it includes variable declarations. – C, C++, and Java use ‘{’ and ‘}’ to delimit a block. – Pascal and Modula use begin... end. – Ada uses declare... begin... end. – Python uses indentation.

10 Sequencing Pure functional languages do not have sequencing, and they do not need it Side effects in functions sometimes desirable def srand(seed) – # Initialize internal tables – # The pseudo-random generator will return a different – # sequence of values for each different value of seed def rand() – # No arguments; returns a new ``random'' number Obviously, rand needs to have a side effect

11 Selection – sequential if statements if... then... else if... then... elsif... else (cond (C1 E1) (C2 E2)... (Cn En) (T Et) )

12 Selection: If-Then-Else From Algol 60: – if condition then statement – else if condition then statement –... – else statement To avoid grammatical ambiguity: – Algol 60 requires begin after then – Pascal requires “disambiguating rule”: associate else with the closest unmatched then – Algol 68, Fortran 77 and modern ones require a terminating keyword Modula-2, Ada use nested if-then-else IF condition THEN statement ELSIF condition THEN statement... ELSE statement END

13 Selection Example: if ((A > B) and (C > D)) or (E <> F) then then_clause else else_clause Code generated w/o short-circuiting (Pascal) r1 := A - load r2 := B r1 := r1 > r2 r2 := C r3 := D r2 := r2 > r3 r1 := r1 & r2 r2 := E r3 := F r2 := r2 $<>$ r3 r1 := r1 $|$ r2 if r1 = 0 goto L2 L1: then_clause goto L3 L2: else_clause L3:

14 Selection Code generated w/ short-circuiting (C) r1 := A r2 := B if r1 r2 goto L1 L4: r1 := E r2 := F if r1 = r2 goto L2 L1: then_clause goto L3 L2: else_clause L3:

15 Selection: case/switch Variant of nested if-then-else statements (thanks to Tony Hoare). Designed for efficient implementation Most programming languages support a switch-like statement C, C++, and Java: switch (value) { case "a": x * 5; break; case "b": x = 7; break; case "c": x – 2; break; default:... } Python: No switch/case statements, but do we need it? result = { "a": lambda x: x * 5, "b": lambda x: x + 7, "c": lambda x: x - 2 }[value](x)

16 Jump Comparison Again Example: CASE... OF 1: clause_A 2,7: claues_B 3..5:clause_C 10:clause_D ELSE:clause_E END r1 :=... if r1 <> 1 goto L1 clause_A goto L6 L1: if r1 <> 2 goto L2 if r1 <> 7 goto L3 L2: clause_B goto L6 L3: if r1 < 3 goto L4 if r1 > 5 goto L4 clause_C goto L6 L4: if r1 <> 10 goto L5 clause_D goto L6 L5: clause_E L6:

17 Jump Comparison Again Example: CASE... OF 1: clause_A 2,7: claues_B 3..5:clause_C 10:clause_D ELSE:clause_E END goto L6 L1: clause_A goto L7 L2: clause_B goto L7 L3: clause_C goto L7 L4: clause_D goto L7 L5: clause_E goto L7 L6: r1 :=... goto *r1 L7:

18 Iteration Enumeration-controlled loops repeat a collection of statements a number of times, where in each iteration a loop index variable takes the next value of a set of values specified at the beginning of the loop. Logically-controlled loops repeat a collection of statements until some Boolean condition changes value in the loop. – Pretest loops test condition at the begin of each iteration. – Posttest loops test condition at the end of each iteration. – Mid-test loops allow structured exits from within loop with exit conditions.

19 Enumeration-Controlled Loops: Pascal Pascal’s enumeration-controlled loops have two simple and elegant forms for up and down: for id := expr to expr do stmt for id := expr downto expr do stmt Can iterate over any discrete type, e.g. integers, chars, elements of a set Evaluate loop bounds exactly once before the first iteration Changes to loop indices or bounds are prohibited in the loop body Final value of loop counter after the loop is undefined

20 Enumeration-Controlled Loops: Python Python’s enumeration-controlled loops only have one form: for id in sequence expr : stmt Can iterate over any sequence types including iterators/generators Changes to loop indices or bounds have no effect in the loop body Final value of loop variable after the loop is the value most recently assigned

21 Enumeration-Controlled Loops: C/C++/C#/Java C/C++/C#/Java do not have true enumeration-controlled loops. A “for” loop is essentially a logically-controlled loop. for (i = 1; i <= n; i++) Changes to loop indices or bounds are allowed in the loop body. Use continue to jump to next iteration Use break to exit loop C++/C#/Java also support local scoping for counter variables for (int i = 1; i <= n; i++)

22 Iterator Iterators are used to iterate over elements of well-defined sets (called containers or collections). Iterator objects are also called enumerators or generators. C++/Java iterators are ordinary objects associated with container objects. In C++, overloading is used to simulate pointer arithmetic in C’s loops vector V; for (vector ::iterator it=V.begin();it!=V.end();it++) cout << *it << endl; In Java, iterator interface provides methods for initialization, generation of the next index value, and testing for completion Vector V; for (Iterator it=V.iterator();V.hasNext();) System.out.println(V.next());

23 Iterator C#/Python/Ruby provide iterators which are functions running in a separate thread from its caller Contains yield statement as well as return statement. The yield behaves like return, except that when the iterator reenteres, the control continues where it last left off. Python’s tree in-order traverse def inorder(t): if t: for x in inorder(t.left): yield x yield t.dat for x in inorder(t.right): yield x

24 Pretest loops Logically-controlled pretest loops check the exit condition before the next loop iteration Pascal: while cond do stmt C/C++: while (cond) stmt Use break to end loops C#/Java: similar to C/C++, but that break can jump to redefined labels

25 Posttest Loops Logically-controlled posttest loops check the exit condition after each loop iteration Pascal: repeat stmt until cond C/C++: do stmt while cond Use break to end loops C#/Java: similar to C/C++, but that break can jump to redefined labels

26 Mid-test Loops Logically-controlled mid-test loops check exit conditions anywhere within the loop Ada: support labels, allowing exit of outer loops without gotos outer:.... loop stmt exit when cond; stmt exit when cond;.... end loop

27 Recursion Recursion: subroutines that call themselves directly or indirectly (mutual recursion) Typically used to solve a problem that is defined in terms of simpler versions Iteration and recursion are equally powerful in theoretical sense; either can be expressed by the other Recursion is more elegant to use to solve a problem that is naturally recursively defined, such as a tree traversal algorithm Recursion can be less efficient, but most compilers for functional languages are often able to replace it with iterations

28 Tail Recursion Tail-recursive functions are functions in which no operations follow the recursive call(s) in the function: the return value is simply whatever the recursive call returns. Tail Recursive: Non-Tail Recursive:def fun():... return fun()return fun()+1 Compilers can reuse the space on the run-time stack that belongs to the current subroutine’s frame Good compilers may even replace tail-recursive calls by jumps to the beginning of the function

29 Tail-Recursion Optimization: An Example Consider the GCD function: def gcd(a, b): if a==b: return a elif a>b: return gcd(a-b,b) else: return gcd(a, b-a) A good compiler will optimize the function into def gcd(a, b): while 1: if a==b: return a elif a>b: a=a-b continue else: b=b-a continue

30 Converting General Recursion to Tail Recursion: An Example General recursive def sum(f, l, h): if l == h: return f(l) else: return f(l)+ sum(f, l+1, h) Tail recursive def sum(f, l, h, s): if l == h: return f(l)+s else: sum(f, l+1, h, s+f(l))

31 Thinking Recursively Naive recursion design leads to algorithmically inferior programs. A naive recursive implementation of Fibonacci function: def fib(n): if n==0: return 1 elif n==1: return 1 else: return fib(n-1)+fib(n-2) runs in time that is exponential in n. A tail-recursive implementation of Fibonacci function def fib(n): def fib_helper(f1,f2,i): if n==i: return f2 else: return fib_helper(f2, f1+f2, i+1) return fib_helper(0,1,0) runs in time that is linear in n.  o 


Download ppt "CSCI 330: Programming Language Concepts Instructor: Pranava K. Jha Control Flow-II: Execution Order."

Similar presentations


Ads by Google