Ordering Within Expressions. Control Flow. Side-effects. Side-effects. Order of Evaluation. Misbehaving Floating-Point Numbers.

Similar documents
Control Flow COMS W4115. Prof. Stephen A. Edwards Fall 2006 Columbia University Department of Computer Science

int foo() { x += 5; return x; } int a = foo() + x + foo(); Side-effects GCC sets a=25. int x = 0; int foo() { x += 5; return x; }

Control Flow. Stephen A. Edwards. Fall Columbia University

LECTURE 18. Control Flow

Control Structures. Outline. In Text: Chapter 8. Control structures Selection. Iteration. Gotos Guarded statements. One-way Two-way Multi-way

Chapter 7. - FORTRAN I control statements were based directly on IBM 704 hardware

CSc 520 Principles of Programming Languages. 26 : Control Structures Introduction

COP4020 Programming Languages. Control Flow Prof. Robert van Engelen

Page # Expression Evaluation: Outline. CSCI: 4500/6500 Programming Languages. Expression Evaluation: Precedence

Statement level control structures

Chapter 6 Control Flow. June 9, 2015

Programming Languages Third Edition. Chapter 9 Control I Expressions and Statements

! Non-determinacy (unspecified order) Maria Hybinette, UGA 2. 1 Landin adding sugar to a language to make it easier to read (for humans)

Chapter 8. Statement-Level Control Structures

Lecture 15: Iteration and Recursion

Chapter 8. Statement-Level Control Structures

The Compiler So Far. CSC 4181 Compiler Construction. Semantic Analysis. Beyond Syntax. Goals of a Semantic Analyzer.

Design Issues. Subroutines and Control Abstraction. Subroutines and Control Abstraction. CSC 4101: Programming Languages 1. Textbook, Chapter 8

Compilers CS S-05 Semantic Analysis

CSE 452: Programming Languages. Outline of Today s Lecture. Expressions. Expressions and Control Flow

SE352b: Roadmap. SE352b Software Engineering Design Tools. W3: Programming Paradigms

Names, Scope, and Bindings

Chapter 8. Statement-Level Control Structures

Names, Scope, and Bindings

Topics Covered Thus Far. CMSC 330: Organization of Programming Languages. Language Features Covered Thus Far. Programming Languages Revisited

1 Lexical Considerations

Chapter 7 Control I Expressions and Statements

Names, Scope, and Bindings

CMSC 330: Organization of Programming Languages

Control Flow. CSE 307 Principles of Programming Languages Stony Brook University

C Language Part 2 Digital Computer Concept and Practice Copyright 2012 by Jaejin Lee

G Programming Languages - Fall 2012

Chapter 8 Statement-Level Control Structures

Abstract Syntax Trees

Implementing Actions

Intermediate Code Generation

Chapter 8. Statement-Level Control Structures ISBN

Ch. 7: Control Structures

Iterative Statements. Iterative Statements: Examples. Counter-Controlled Loops. ICOM 4036 Programming Languages Statement-Level Control Structure

G Programming Languages Spring 2010 Lecture 4. Robert Grimm, New York University

CSC 533: Organization of Programming Languages. Spring 2005

Topics Covered Thus Far CMSC 330: Organization of Programming Languages

Names, Scope, and Types

MIDTERM EXAMINATION - CS130 - Spring 2003

CSE 374 Programming Concepts & Tools

Object Code (Machine Code) Dr. D. M. Akbar Hussain Department of Software Engineering & Media Technology. Three Address Code

9/21/17. Outline. Expression Evaluation and Control Flow. Arithmetic Expressions. Operators. Operators. Notation & Placement

COMP-520 GoLite Tutorial

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

CS 314 Principles of Programming Languages. Lecture 9

Object-oriented programming. and data-structures CS/ENGRD 2110 SUMMER 2018

Lecture 9: Control Flow

Lexical Considerations

What is a compiler? var a var b mov 3 a mov 4 r1 cmpi a r1 jge l_e mov 2 b jmp l_d l_e: mov 3 b l_d: ;done

LECTURE 17. Expressions and Assignment

Language Design COMS W4115. Prof. Stephen A. Edwards Fall 2006 Columbia University Department of Computer Science

G Programming Languages - Fall 2012

LECTURE 3. Compiler Phases

Principle of Complier Design Prof. Y. N. Srikant Department of Computer Science and Automation Indian Institute of Science, Bangalore

Intel x86 Jump Instructions. Part 5. JMP address. Operations: Program Flow Control. Operations: Program Flow Control.

Control Flow. COMS W1007 Introduction to Computer Science. Christopher Conway 3 June 2003

Subprograms. Akim D le Étienne Renault Roland Levillain EPITA École Pour l Informatique et les Techniques Avancées

Expressions vs statements

Intel x86 Jump Instructions. Part 5. JMP address. Operations: Program Flow Control. Operations: Program Flow Control.

An Introduction to Scheme

Lexical Considerations

LECTURE 1. Overview and History

Expressions and Statements. Department of CSE, MIT, Manipal

Flow of Control Execution Sequence

CS S-06 Semantic Analysis 1

Type Conversion. and. Statements

NOTE: Answer ANY FOUR of the following 6 sections:

A Deterministic Concurrent Language for Embedded Systems

Programming Language Pragmatics

Review of the C Programming Language

Introduction Primitive Data Types Character String Types User-Defined Ordinal Types Array Types. Record Types. Pointer and Reference Types

CS 415 Midterm Exam Fall 2003

General Concepts. Abstraction Computational Paradigms Implementation Application Domains Influence on Success Influences on Design

CSE 307: Principles of Programming Languages

Compiler construction

The C Language COMS W Prof. Stephen A. Edwards Fall 2002 Columbia University Department of Computer Science

What is a compiler? Xiaokang Qiu Purdue University. August 21, 2017 ECE 573

4. Functions. March 10, 2010

Organization of Programming Languages (CSE452) Why are there so many programming languages? What makes a language successful?

CMPT 379 Compilers. Anoop Sarkar. 11/13/07 1. TAC: Intermediate Representation. Language + Machine Independent TAC

Weeks 6&7: Procedures and Parameter Passing

CS 415 Midterm Exam Spring 2002

Compilers. Type checking. Yannis Smaragdakis, U. Athens (original slides by Sam

Expressions & Flow Control

Programming Languages

The Structure of a Syntax-Directed Compiler

MIDTERM EXAMINATION - CS130 - Spring 2005

22c:111 Programming Language Concepts. Fall Types I

Review for the Final

Time : 1 Hour Max Marks : 30

Sequence structure. The computer executes java statements one after the other in the order in which they are written. Total = total +grade;

The New C Standard (Excerpted material)

CS558 Programming Languages

An ANTLR Grammar for Esterel

Programming for Engineers Iteration

Transcription:

Control Flow COMS W4115 Prof. Stephen A. Edwards Spring 2003 Columbia University Department of Computer Science Control Flow Time is Nature s way of preventing everything from happening at once. Scott identifies seven manifestations of this: 1. Sequencing foo(); bar(); 2. Selection if (a) foo(); 3. Iteration while (i<10) foo(i); 4. Procedures foo(10,20); 5. Recursion foo(int i) { foo(i-1); 6. Concurrency foo() bar() 7. Nondeterminism do a -> foo(); [] b -> bar(); Ordering Within Expressions What code does a compiler generate for a = b + c + d; Most likely something like tmp = b + c; a = tmp + d; (Assumes left-to-right evaluation of expressions.) Order of Evaluation Why would you care? Expression evaluation can have side-effects. Floating-point numbers don t behave like numbers. Side-effects int x = 0; int foo() { x += 5; return x; int a = foo() + x + foo(); What s the final value of a? Side-effects int x = 0; int foo() { x += 5; return x; int a = foo() + x + foo(); GCC sets a=25. Sun s C compiler gave a=20. C says expression evaluation order is implementation-dependent. Side-effects Java prescribes left-to-right evaluation. class Foo { static int x; static int foo() { x += 5; return x; public static void main(string args[]) { int a = foo() + x + foo(); System.out.println(a); Always prints 20. Number Behavior Basic number axioms: a + x = a if and only if x = 0 Additive identity (a + b) + c = a + (b + c) Associative a(b + c) = ab + ac Distributive Misbehaving Floating-Point Numbers 1e20 + 1e-20 = 1e20 1e-20 1e20 (1 + 9e-7) + 9e-7 1 + (9e-7 + 9e-7) 9e-7 1, so it is discarded, however, 1.8e-6 is large enough 1.00001(1.000001 1) 1.00001 1.000001 1.00001 1 1.00001 1.000001 = 1.00001100001 requires too much intermediate precision.

What s Going On? Floating-point numbers are represented using an exponent/significand format: 1 10000001 {{ 01100000000000000000000 {{ 8-bit exponent 23-bit significand = 1.011 2 2 129 127 = 1.375 4 = 5.5. What to remember: 1363.456846353963456293 {{{{ represented rounded What s Going On? Results are often rounded: 1.00001000000 1.00000100000 1.000011 00001 {{ rounded When b c, b + c is small, so ab + ac a(b + c) because precision is lost when ab is calculated. Moral: Be aware of floating-point number properties when writing complex expressions. Short-Circuit Evaluation When you write if (disaster_could_happen) avoid_it(); else cause_a_disaster(); cause_a_disaster() is not called when disaster_could_happen is true. The if statement evaluates its bodies lazily: only when necessary. Short-Circuit Evaluation The section operator? : does this, too. cost = disaster_possible? avoid_it() : cause_it(); cause_it is not called if disaster_possible is true. Logical Operators In Java and C, Boolean logical operators short-circuit to provide this facility: if (disaster_possible case_it()) { cause_it() only called if disaster_possible is false. The && operator does the same thing. Useful when a later test could cause an error: int a[10]; Short-Circuit Operators Not all languages provide short-circuit operators. Pascal does not. C and Java have two sets: Logical operators && short-circuit. Boolean (bitwise) operators & do not. if (i => 0 && i < 10 && a[i] == 0) { Unstructured Control-Flow Assembly languages usually provide three types of instructions: Pass control to next instruction: add, sub, mov, cmp Pass control to another instruction: jmp rts Conditionally pass control next or elsewhere: beq bne blt Unstructured Control-Flow So-called because it s easy to create spaghetti: beq A B: jmp C A: beq D C: beq B D: bne B Structured Control-Flow The object-oriented languages of the 1960s and 70s. Structured programming replaces the evil goto with structured (nested) constructs such as if-then-else for while do.. while break continue return

Gotos vs. Structured Programming A typical use of a goto is building a loop. In BASIC: 10 print I 20 I = I + 1 30 IF I < 10 GOTO 10 A cleaner version in C using structured control flow: do { printf("%d\n", i); i = i + 1; while ( i < 10 ) An even better version for (i = 0 ; i < 10 ; i++) printf("%d\n", i); Gotos vs. Structured Programming Break and continue leave loops prematurely: for ( i = 0 ; i < 10 ; i++ ) { if ( i == 5 ) continue; if ( i == 8 ) break; printf("%d\n", i); Again: if (!(i < 10)) goto Break; if ( i == 5 ) goto Continue; if ( i == 8 ) goto Break; printf("%d\n", i); Continue: i++; goto Again; Break: Escaping from Loops Java allows you to escape from labeled loops: a: for (int i = 0 ; i < 10 ; i++) for ( int j = 0 ; j < 10 ; j++) { System.out.println(i + "," + j); if (i == 2 && j == 8) continue a; if (i == 8 && j == 4) break a; Gotos vs. Structured Programming Pascal has no return statement for escaping from functions/procedures early, so goto was necessary: procedure consume_line(var line : string); begin if line[i] = % then goto 100; (*. *) 100: end In C and many others, return does this for you: void consume_line(char *line) { if (line[0] == % ) return; Loops A modern processor can execute something like 1 billion instructions/second. How many instructions are there in a typical program? Perhaps a million. Why do programs take more than 1µs to run, then? Answer: loops This insight is critical for optimization: only bother optimizing the loops since everything else is of vanishing importance. Enumeration-Controlled Loops in FORTRAN do 10 i = 1, 10, 2 10: continue Executes body of the loop with i=1, 3, 5,..., 9 Tricky things: What happens if the body changes the value of i? What happens if gotos jump into or out of the loop? What is the value of i upon exit? What happens if the upper bound is less than the lower one? Changing Loop Indices Most languages prohibit changing the index within a loop. (Algol 68, Pascal, Ada, FORTRAN 77 and 90, Modula-3) But C, C++, and Java allow it. Why would a language bother to restrict this? Prohibiting Index Modification Optimizing the behavior of loops is often very worthwhile. Some processors have explicit looping instructions. Some compilers transform loop index variables for speed or safety. Letting the program do whatever it wants usually prevents optimizations. Empty Bounds In FORTRAN, the body of this loop is executed once: do 10 i = 10, 1, 1 10: continue for i = 10 to 1 by 1 Test is done after the body.

Empty Bounds Modern languages place the test before the loop. Does the right thing when the bounds are empty. Slightly less efficient (one extra test). Scope of Loop Index What happens to the loop index when the loop terminates? Index is undefined: FORTRAN IV, Pascal. Index is its last value: FORTRAN 77, Algol 60 Index is just a variable: C, C++, Java Tricky when iterating over subranges. What s next? var c : a.. z ; for c := a to z do begin end; (* what s c? *) Scope of Loop Index Originally in C++, a locally-defined index variable s scope extended beyond the loop: for (int i = 0 ; i < 10 ; i++) { a = a + i; // Was OK: i = 10 here But this is awkward: for (int i = 0 ; i < 10 ; i++) { for (int i = 0 ; i < 10 ; i++) // Error: // i redeclared Scope of Loop Index C++ and Java now restrict the scope to the loop body: for (int i = 0 ; i < 10 ; i++ ) { int a = i; // OK int b = i; // Error: i undefined for (int i = 0 ; i < 10 ; i++ ) { // OK Rather annoying: broke many old C++ programs. Better for new code. Algol s Combination Loop for for id := for-list do stmt for-list enumerator (, enumerator )* enumerator expr expr step expr until expr expr while condition Equivalent: for i := 1, 3, 5, 7, 9 do for i := 1 step 2 until 10 do for i := 1, i+2 while i < 10 do Language implicitly steps through enumerators (implicit variable). Algol s Combination Loop Needlessly general, it turns out. C s logically controlled loop retains most of the functionality: for ( i = 1 ; i < 10 ; i += 2 ) { is equivalent to i = 1; while (i < 10) { i += 2; Pre- and Post-test Loops Most loops want their tests first to allow the possibility of zero iterations. struct foo *p = head; // Sum a linked list while (p!= 0) { total += p->value; p = p->next; But it s sometimes useful to place the test at the end: char line[80]; do { scanf("%s", line); while (line[0] == # ); /* skip comments */ Mid-test Loops while true do begin readln(line); if all_blanks(line) then goto 100; consume_line(line); end; 100: LOOP line := ReadLine; WHEN AllBlanks(line) EXIT; ConsumeLine(line) END; Mid-test Loops loop statements when condition exit statements when condition exit end Advantage: a syntactic construct. Errors caught in parser. Compare with Tiger s break, which must fall within a while or for. More difficult to check (static semantics).

Multi-way Branching switch (s) { case 1: one(); break; case 2: two(); break; case 3: three(); break; case 4: four(); break; Switch sends control to one of the case labels. Break terminates the statement. Implementing multi-way branches switch (s) { case 1: one(); break; case 2: two(); break; case 3: three(); break; case 4: four(); break; Obvious way: if (s == 1) { one(); else if (s == 2) { two(); else if (s == 3) { three(); else if (s == 4) { four(); Reasonable, but we can sometimes do better. Implementing multi-way branches If the cases are dense, a branch table is more efficient: switch (s) { case 1: one(); break; case 2: two(); break; case 3: three(); break; case 4: four(); break; labels l[] = { L1, L2, L3, L4 ; /* Array of labels */ if (s>=1 && s<=4) goto l[s-1]; /* not legal C */ L1: one(); goto Break; L2: two(); goto Break; L3: three(); goto Break; L4: four(); goto Break; Break: Recursion and Iteration Consider computing 10 f(i) i=0 In C, the most obvious evaluation is iterative: double total = 0; for ( i = 0 ; i <= 10 ; i++ ) total += f(i); Recursion and Iteration 10 f(i) i=0 But this can also be defined recursively double sum(int i) { double fi = f(i); if (i <= 10) return fi + sum(i+1); else return fi; sum(0); Recursion and Iteration Grammars make a similar choice: Iteration: clist : item ( "," item )* ; Recursion: clist : item tail ; tail : "," item tail /* nothing */ ; Tail-Recursion and Iteration int gcd(int a, int b) { if ( a==b ) return a; else if ( a > b ) return gcd(a-b,b); else return gcd(a,b-a); Notice: no computation follows any recursive calls. Stack is not necessary: all variables dead after the call. Local variable space can be reused. Trivial since the collection of variables is the same. Tail-Recursion and Iteration int gcd(int a, int b) { if ( a==b ) return a; else if ( a > b ) return gcd(a-b,b); else return gcd(a,b-a); Can be rewritten into: int gcd(int a, int b) { start: if ( a==b ) return a; else if ( a > b ) a = a-b; goto start; else b = b-a; goto start; Tail-Recursion and Iteration Good compilers, especially those for functional languages, identify and optimize tail recursive functions. Less common for imperative languages. But gcc -O was able to rewrite the gcd example.

Applicative- and Normal-Order Evaluation int p(int i) { printf("%d ", i); return i; void q(int a, int b, int c) { int total = a; printf("%d ", b); total += c; What is printed by q( p(1), 2, p(3) ); Applicative- and Normal-Order Evaluation int p(int i) { printf("%d ", i); return i; void q(int a, int b, int c) { int total = a; printf("%d ", b); total += c; q( p(1), 2, p(3) ); Applicative: arguments evaluated before function is called. Result: 1 3 2 Normal: arguments evaluated when used. Result: 1 2 3 Applicative- vs. and Normal-Order Most languages use applicative order. Macro-like languages often use normal order. #define p(x) (printf("%d ",x), x) #define q(a,b,c) total = (a), \ printf("%d ", (b)), \ total += (c) q( p(1), 2, p(3) ); Prints 1 2 3. Some functional languages also use normal order evaluation to avoid doing work. Lazy Evaluation Argument Order Evaluation C does not define argument evaluation order: int p(int i) { printf("%d ", i); return i; int q(int a, int b, int c) { q( p(1), p(2), p(3) ); Might print 1 2 3, 3 2 1, or something else. This is an example of nondeterminism. Nondeterminism Nondeterminism is not the same as random: Compiler usually chooses an order when generating code. Optimization, exact expressions, or run-time values may affect behavior. Bottom line: don t know what code will do, but often know set of possibilities. int p(int i) { printf("%d ", i); return i; int q(int a, int b, int c) { q( p(1), p(2), p(3) ); Will not print 5 6 7. It will print one of 1 2 3, 1 3 2, 2 1 3, 2 3 1, 3 1 2, 3 2 1 Nondeterminism Nondeterminism lurks in most languages in one form or another. Especially prevelant in concurrent languages. Sometimes it s convenient, though: if a >= b -> max := a [] b >= a -> max := b fi Nondeterministic (irrelevant) choice when a=b. Often want to avoid it, however.