Coverage • Variables • Type Checking • Scope • Referencing Environments • Data Types • Arithmetic Expressions • Control Flow • Stack and Subprograms • Programming for Imperative Features Imperative Languages 1 Introduction • Imperative languages are based on the concept of Von Neumann machines where memory is separated from Central Processing Unit (CPU); data and programs are stored in the same memory. • Instructions and data are piped from memory to CPU for further processing. • Von Neumann machines have general purpose registers and Arithmetic Logic Unit (ALU). • Instruction cycle proceeds by fetching the instruction, updating the program counter and then executing the instruction. • Direct Memory Access (DMA) provides transfer of data from or to Input-Output (I/O) devices and to or from memory by stealing memory cycles from CPU. Imperative Languages 2 Variables • Languages is said to be turing complete if it has integer variables, integer values, integer operations, assignment statements, statement sequences, conditionals and branching statements • Names or identifiers are used to refer to variables, procedures, constants, etc • User-defined Names or identifiers − Length, Case sensitivity • COBOL: maximum variable length is 30 characters • FORTRAN 90 and ANSI C: maximum 31 characters • Ada, C# and Java: There is no limit on the length • C++: no limit, but implementers often impose one • C, C+ and Java: Case sensitive in nature Imperative Languages 3 Variables • Pascal and C: Variables are to be declared before use • The name of a variable is used to identify and refer to the variable. • Scope of a variable is the segment of the program within which it is defined. • Visibility of a variable is visible within some sub-segment if it can be directly accessed using its name. • Lifetime of a variable is the time period from the allocation of memory to the variable to when the memory is de-allocated, during program execution. • Lifetime is a dynamic property while scope and visibility are static properties • Address is the memory location associated with the variable and it is called as l-value (left value or locator value) • Value (called as r-value or right value) is the actual contents of the memory location of the variable Imperative Languages 4 Variables • Type of the variables controls the range of values and the set of operations that could be performed • The byte data type in Java is of one byte with values ranging from 128 to 127; short data type in Java is of two bytes with data ranging from -32768 to 32767 • The process of associating an attribute to an entity is called as Binding. The process of associating an operation and a symbol is also called as Binding. • Language design time: − Also called Language definition time − Programmer is given a definite set of syntax and program structures − Example: Operators with their respective operations, data types, … − In C language, new data types can be defined, ex., struct. Imperative Languages 5 Binding Time • • • • Language implementation time: − Binding might vary among different implementations of the same language − Depends on hardware architecture and operating system − Floating point data type representation Compile time: − Also called as Translation time binding − Binding of variables to its type in C or Java − Allocation of memory for arrays or relative memory allocations Load time: − Also called Link time − Binding the variables to the memory cell during loading time as in static variables of C language and Fortran 77 variables − Task is handled by loader or linker Runtime: − Also called Execution time binding − Binding non-static variable to the respective memory cell is done at runtime − Binding of formal to actual parameters needs to be done at runtime Imperative Languages 6 Variable Binding • The process of binding a variable during compile time or load time or at the beginning of runtime is called early binding. • If the binding happens during later stages of the runtime, then it is called late binding. • In C#: − Generic data type Object is bounded using late binding while a specific object type is bounded using early binding • Static binding occurs before run time and remains unchanged throughout program execution • Dynamic binding occurs during execution or can change during the execution of the program • JavaScript and PHP use dynamic binding Imperative Languages 7 Variable Binding • Dynamic binding example in JavaScript − <script type="text/JavaScript"> − var myList = [1,2,3]; − document.write("myList[0] = " + myList[0]+ " "); // 1 − var myInteger = 45; − document.write("myInteger[0] = " + myInteger[0]+ " "); // undefined − document.write("myInteger = " + myInteger+ " "); // 45 − myList = myInteger; // List is overwritten by the integer element − document.write("myList[0] = " + myList[0]+ " "); // undefined − document.write("myList = " + myList+ " "); // 45 − var myArray = new Array(); − myArray[0]="India"; − myArray[1]="Brunei Darussalam"; − myList = myArray; // List overwritten by the array elements. − document.write("myList[0] = " + myList[0]+ " "); // India − document.write("<BR>"); − </script> • Doing something similar in C or C++ or Java will generate an error. Imperative Languages 8 Variables • • • Type inferencing − Type of the variable is based on the context of the reference and not by the assignment statement − Used in ML, Miranda and Haskell Variable type declaration − Explicit: Specified with a statement − Implicit: Inferred from the first assignment • Example: FORTRAN, PL/I, BASIC and Perl Lifetime of a variable − Static: • Variable is bound to a memory cell before execution and it remains bounded to the same memory variable throughout execution • Example: Fortran 77 variables, C or C# static variables − Stack-dynamic: • Variable is bound to a memory cell during the process of elaboration of the declaration of the variable. • This process happens during program execution • Example: local variables in C subprogram and Java methods • Variables defined in methods of Java or C++ or C# are by default stack-dynamic. Imperative Languages 9 Lifetime of a variable • Lifetime of a variable − Explicit heap-dynamic: • Allocation and de-allocation are done explicitly using certain directives from the programmer. • They are referenced through pointers or references • Example: all objects in Java and dynamic objects created in C++ using new and delete methods • In C#, objects defined using class keyword are allocated on the heap but those defined using struct keyword are stack allocated. − Implicit heap-dynamic: • Allocation and de-allocation is caused by assignment statements • Example: all variables in APL (A Programming Language), all strings and arrays in Perl and JavaScript. Imperative Languages 10 Pointer variable • Pointers are used to refer to memory locations where variables are stored • Used in Pascal [called as dynamic variables, referred using ^ operator], C, C++, C# [with unsafe], etc • In C: & is used to refer to memory location and * is used to refer to the contents of the memory location • In C, void * is a generic pointer. Generic pointer cannot be dereferenced and thus pointer arithmetic operations can not be applied on them Imperative Languages 11 Pointer variable 12 • • • • • #include <stdio.h> int main() { int a = 5; int b = 10; int *ptra = &a; // ptra is a pointer to a • • • • int *ptrb = &b; // ptrb is a pointer to b *ptra = *ptrb; // a and b will have the same value printf("*ptra = %d, *ptrb = %d\n", *ptra, *ptrb); printf("a = %d, b = %d\n", a, b); • • • • • if (ptra == ptrb) printf("%s", "ptra and ptrb are the same\n"); else printf("%s", "ptra and ptrb are not the same\n"); if (*ptra == *ptrb) printf("%s", "*ptra and *ptrb are the same\n"); ptra = ptrb; // pointers now point only to b printf("a = %d, b = %d\n", a, b); 5 ptra a 10 ptrb b After the statement: ptra = ptrb; ptra • Return 0; • } 5 a 10 ptrb Imperative Languages b Type Checking 13 • Make sure that the operands and the operator are of compatible types • Errors detected during type checking are called as type errors • Process of conversion of one type to another by the compiler itself is called as coercion • If all type bindings are static, nearly all type checking can be static. If type bindings are dynamic, then type checking must also be dynamic. • A language which could catch all type errors is called strongly typed language. Imperative Languages Type Checking 14 • Holding different values at different times − Pascal: variant records − C or C++: union inside struct • In C and C++, parameter type checking can be avoided and unions are not type checked • Ada and Java are almost strongly typed languages Imperative Languages Type Checking 15 • ML and Haskell are strongly typed languages • Fortran 77, Pascal, C and C++ are not considered as strongly typed languages • Languages that are without static type systems are called as untyped languages or dynamically typed languages − Example: Scheme, Smalltalk, Perl, … • Static or Translation-time Type Checking − Checking for type errors at translation stage − Will indicate type errors earlier • Attaching types to expressions is called as type inferencing − − − − int main( ) { float value; value = 10/3; printf("%f\n",value); return 0; } This program returns 3.000000. To get 3.333333, we need to use 10.0/3 or 10/3.0 Imperative Languages Type Equivalence • Type restrictions on structured types − − − − • In Pascal, formal parameters (parameter present in the subprogram) must be of the same type as their corresponding actual parameters (parameter present in the subprogram call). In Pascal, Subranges, which has a limited range of allowed values of integer types, is not compatible with integer types For example, a range 10 ... 12 is a subrange of integer type Subrange type is not present in C++ or Java. Structure type compatibility or structure equivalence − − − − Equal only if they have identical structures Two records having the same structure but different field names should be considered compatible or not. Two array having the same type but different subscript should be considered compatible or not. Two enumerations with their components spelled differently should be considered compatible or not. Imperative Languages 16 Type Equivalence • C language: Following two arrays are structurally equivalent. − − • Same size and same content int a[3] = {1,2,3}; int b[3] = {1,2,3}; Name equivalence: − Needs to be of same name • C language: struct does not imply structure equivalent • struct x { int a; }; struct y { int a; }; • typedef struct {int x1; char z;} Rec1; typedef Rec1 Rec2; • typedef struct {int x2; char z;} Rec3; • int main() { struct x z, a2; struct y a1; • z = a2; z = a1; // z = a2 has no error but z = a1 has compile error • Rec1 a, b; Rec2 c; Rec3 d; a = b; // Name equivalence • a = c; // Name equivalence • // a = d; // Generates compilation error. } Imperative Languages 17 Type Equivalence • Declaration equivalence − − − − • Must have the same original structure if traced backwards a and b are considered declaration equivalent. int a[10], b[10]; typedef char * string; string a; char *b; Pascal − − Parameter type checking is using Name Equivalence Other types check is upto the implementation Imperative Languages 18 Type Equivalence • C or C++: − • Supports structured type compatibility except for records or struct Java: − Does not support structure equivalent in classes. • class C1 { int x, y; } • class C2 { int x, y; } • public class Equivalence • {public static void main(String[] args) • { C1 a = new C1(); C1 c = new C1(); • a = c; // works ok. • C2 b = new C2(); • a = b; // Compilation error - incompatible. • C1 z = new C2(); // Compilation error. • } • } Imperative Languages 19 Scope • Scope of any variable is the range of statements over which it is visible − • Depends on the location of the declaration of the variable Local variables override global variables Handled during translation or compile time itself Dynamic Scope: − − • Lexical scope: Depends on where the variable is defined. Static Scope − − − • 20 Based on the flow of execution of the program Dynamic scope makes the reference convenient but readability is affected. Scope and lifetime are sometimes closely related but are different concepts Imperative Languages Scope • What is the output of this C program? − x is printed as 110 as static scope is used. Imperative Languages 21 Referencing Environments • Referencing environment of a statement indicates the collection of all names that are visible in the statement − − • 22 Static-scoped language: local variables and visible variables of the enclosing scopes Dynamic-scoped languages: local variables and visible variables of all active subprograms Components of referencing environment: − − Local referencing environment: • Called as local environment • Formal parameters, local variables and subprograms that are defined as part of current subprogram Global referencing environment: • Global associations that are available during the current execution Imperative Languages Referencing Environments • Components of referencing environment: − − • 23 Non-local referencing environment: • Associations that are not created on entry into subprogram Predefined referencing environment: • Associations defined in the language definition itself Named constant: − − Value is bound to the variable only when the storage is bounded Can be done statically (called as manifest constants) or dynamically − Pascal has literals only − Fortran 90 has constant-valued expression where all terms are either literal or named constants; − Ada and C++ allow named constants to be dynamically bounded to values. • // C++ named constant dynamically bounded. • const int area = side * side; Imperative Languages Referencing Environments • Java has named constants dynamically bounded, with an additional reserved word final. • class Constants { public static void main(String[] args) • { int side = 20; final int length = 20; final int area = side * side; • System.out.println(length); // Prints 20 • System.out.println(area); // Prints 400 • } } • In C#, there are two types of named constants: const and readonly. − Const-named constants have value assigned at compile time and can not be changed once established − Readonly-named constants have value assigned at run time and can not changed once established − Readonly-named constants can be assigned in a constructor but const-named constants can not be assigned in a constructor Imperative Languages 24 Referencing Environments • In C#, there are two types of named constants: const and readonly. − Readonly is an access privilege where the value can be changed from the owner but not from outside. • const double PI = 3.14159; • readonly double PI = 3.14159; • Binding of a variable to a value at the time it is bound to the storage is called initialization. Initialization is mostly done during the declaration statement. − For example, in Java, int sum = 0; Imperative Languages 25 Data Types • Various data types: primitive data types, character string types, userdefined ordinal types, array types, associative arrays, record types, union types and pointer types • Primitive Data Types − Not represented or defined in terms of any other data type − Called as Scalar Structure as only one occurrence of data type is held at any time − Integer: signed or unsigned; byte, short, int, long − Floating point: IEEE 754 Floating Point representation • Represented using sign, exponent and mantissa • C language: float (32 bits), double (64 bits) − Decimal: Numbers with fixed digits like money, cost, etc − Boolean: bits represented as bytes − Character: numeric codes like ASCII or Unicode Imperative Languages 26 Data Types • C language does not have Boolean data type: − typedef enum {false, true} bool; − int main() − { int i = 10; typedef enum {false, true} bool; bool bv; − bv = i + 20; − printf("Integer Value = %d\nBoolean Value = %d\n", i, bv); − return 0; } − The boolean variable bv is stored with an integer number 30. Imperative Languages 27 Boolean Data Type • C++ language with bool data type: − Non-zero (including negative values) represent true and zero represents false • #include <iostream> // iostream.h is depreciated • using namespace std; // needed for cout to work • // if namespace std is not used, cout must be represented as std::cout • // similarly, all functions should be with respective namespace • int main() • { int i = 10; bool bv = true; cout << bv << endl; • bv = i + 20; cout << bv << endl; return 0; } • This program returns the binary value as 1, even after the assignment statement. This is because C++ considers any non-zero value as 1. • In C#, assigning an integer value to bool variable gives an error. It should be assigned as: bool variablename = true; Imperative Languages 28 String Data Type • Sequence of characters and so a non-scalar structure • C language: String is considered as a character array − − − − − − − − − − #include <stdio.h> int main() { char x[10]; // x[0] = "H"; // No compilation error, but nothing is printed. // Usage of double-quotes is wrong. x[0] = 'H'; x[1] = 'e'; x[2] = '\0'; printf("%s\n",x); return 0; } Imperative Languages 29 User-defined Ordinal Types • Ordinal types are of a set provided in a discrete order • Discrete order is of first element, last element and the presence of previous and next elements • Enumeration type − Consists of all possible values that are considered as symbolic constants − C or C++ language: • enum Name {Sat, Sun, Mon, Tue, Wed, Thu, Fri}; • enum Name x = Sat; // x is the variable • Name x; // x is the variable – Not allowed in C • x++; // Allowed in C but not in C++ • int a = Sat; printf("%d\n",a); // Allowed in C and C++ • // this is equivalent to #define Zero 0; #define One 1 • enum {Zero, One}; printf("%d\n",Zero}; // Prints 0 • C# language: public enum Days {Mon, Tue, Wed, Thu, Fri, Sat, Sun}; Imperative Languages 30 User-defined Ordinal Types • Subrange type − Users should provide the ordered contiguous subsequence of an ordinal type. − In Pascal: type Month = 1 .. 12; Imperative Languages 31 Arrays • Collection of homogeneous data elements, positioned relative to the first element • Called as homogeneous structures • If the array index crosses the boundary of the array, an array boundary error occurs. Exception to this is COBOL language. • Issues in handling arrays: − What types are considered legal subscripts? − If the subscript is represented as an expression, are they checked for range? − When does the language allocate space for the array? − How many subscripts are allowed for an array? − Is it a must to initialize the array objects? − Can we allocate the subscript in two different ranges? Imperative Languages 32 Arrays • Types of Arrays: − Static Array: • Storage allocation is static and subscript range is statically bounded • No allocation or de-allocation of locations during runtime. − Fixed stack dynamic array: The range is statically bounded but the allocation is done during execution. − Stack-dynamic array: Allocation is dynamic and subscript range is also dynamically bound. But, once the range is fixed, it stays as it is. − Fixed heap-dynamic array: Subscript range is dynamic and allocation is also dynamic but once they are bounded, they stay as it is. − Heap-dynamic array: Subscript range and allocation are dynamic and changes could be done any number of times during the lifetime of the array. Imperative Languages 33 Arrays • Arrays declared as static in C or C++ functions are static arrays • Arrays not declared as static in C or C++ functions are fixed stackdynamic arrays • Arrays in Ada language are stack dynamic • Arrays in Java are fixed heap dynamic arrays • Heap-dynamic arrays could be created in C# using the class ArrayList. • With regards to array initialization: − Perl does it as: @a = (1..12); − C and C++ language: int group [] = {1,2,3,4,6}; − C# language: int[] group = new int[]{1,2,3,4,6}; Imperative Languages 34 Arrays • Array slicing: Slice is some substructure of an array. It could be used if there are certain operations to be performed on a part of the array. − In Perl, @_ is the list of incoming parameters to a sub. − sub sortArray { − # @_ stands for the parameter passed to the sub. − my $n = @_ - 1; − @_[0..$n] = sort(@_[0..$n]); − } • • C and Java have array index starting with 0 • Unlike C, Java allows the size of the array to be specified dynamically because it is dynamically heap allocated • Once the array size is specified, the size cannot be changed in Java. Imperative Languages 35 Associative Array • Unordered collection of data elements that are indexed by an equal number of values called keys • In Perl, names begin with % and literals are delimited by parenthesis. − %hi_temps=("Monday"=>1,"Tuesday"=>2,…); • Subscripting is done using braces and keys − $hi_temps{"Wednesday"} = 3; • Elements can be removed with delete − delete $hi_temps{"Tuesday"}; Imperative Languages 36 Associative Array • Associative arrays can be implemented in C++ as: • #include <string> • #include <map> • #include <iostream> • int main() • { // studentrecord is a map from string to int • std::map<std::string, int> studentrecord; • studentrecord["Hazwan"] = 11; // Hazwan's ID is 11 • studentrecord ["Atul"] = 12; // Atul's ID is 12 • std::cout << "Atul's ID is " << studentrecord["Atul"] << std::endl; • } Imperative Languages 37 Records and Unions • Record is a heterogeneous aggregate of data elements in which each individual element is identified by its name. − C++ struct is an example of records • Union is similar to record by grouping heterogeneous elements but only one value is stored at a time • In C++, union within struct definition is called as anonymous union. • Java does not possess both records and unions. • Ada has a safe union mechanism called variant record where the discriminant (which gives the type of data being stored) and the actual value are stored at the same time • Example when different information is stored at different time: − For a train travel, the speed is applicable only when the train is travelling between stations. But when the train stops at a station, the speed element is not applicable − Using arrays to store the information will waste spaces when speed is not applicable Imperative Languages 38 Records and Unions • Pascal supports variant records, which could store different values of different types at different times • • • • • • • • • • • • • • • • • • • • program main(input,output); type day = (weekday,weekend); var employee : record name : String; dept: String; salary: real; case daytype : day of weekday: (officephone : integer); weekend: (housephone : integer; houseaddress : String); end; begin employee.name:='Seyed Abdur Rahman'; employee.dept:='Language'; employee.salary:= 20000.00; employee.daytype:=weekday; employee.officephone:= 23333; writeln(employee.name,' ',employee.dept); writeln(employee.officephone); writeln(employee.salary:6:2); {there should be no housephone because daytype=weekday} // the value printed is same as officephone writeln(employee.housephone); employee.daytype:=weekend; employee.housephone:= 22222; employee.houseaddress:='Mohideen Street, Kayalpatnam'; writeln(employee.housephone,' ',employee.houseaddress); end. Imperative Languages 39 Records and Unions 40 • Example in C language: • typedef union { • typedef struct { char *name; int id; uniondata details; • int marks; char grade; } uniondata; int main() { • StudentRecord sturec; • sturec.name = "Noorul Haq"; • sturec.details.marks = 84; • } StudentRecord; sturec.id = 123456; sturec.details.grade = 'X'; printf("Name = %s\n",sturec.name); printf("ID = %d\n",sturec.id); • printf("Marks="%d\n",sturec.details.marks); • printf("Marks=%c\n",sturec.details.grade); • return 0; } • Output: − − − − Name = Noorul Haq ID = 123456 Marks=88 Grade=X Imperative Languages Arithmetic Expressions • Arithmetic expression consists of operators, operands, parenthesis and function calls − Operator precedence rules: • Describes how the expression is evaluated if adjacent operators are of different precedence levels • Typical precedence levels follow higher to lower precedence in this order: Parenthesis, unary operators, **, * or / , + or − Operator associativity rules: • Describes how the expression is evaluated if adjacent operators are of same precedence level • Typical associativity rules are: left to right except for ** which is right to left Imperative Languages 41 Arithmetic Expressions 42 − Order of operator evaluation: • Typical evaluation order is: values of the variables are fetched; constant values are fetched either from memory or from the instruction itself; evaluate all operands and operators first, with priority for parenthesized expressions; functional references are handled. • Functional site effects: Function might change the value of a two-way parameter or a non-local variable • To prevent these side effects, we do either of the following: − Disallow functional side effects by having no two-way parameters and no non-local variables in functions. This will work but will prevent the flexibility of programming. − Write language definition that the operand evaluation order be fixed. This might create some impact on the compiler optimizations. Imperative Languages Arithmetic Expressions 43 • Usage of user-defined operator overloading: − One operator is used for more than one purpose − + operator is used for both int and float types − * operator is used for referencing pointers and multiplication in C and C++ − Usage of overloaded operations might prevent compiler error detection and reduce readability − User-defined overload operators are allowed in C++ and Ada − Java does not support user-defined operator overloading. • Using mixed modes within expressions: Mixed mode expression is one that has operands of different types. • Restrictions on operand evaluation side effects. • Arithmetic expressions could use unary operator that has one operand or binary operator that has two operands or ternary operator that has three operands. Imperative Languages Type Conversions 44 • Narrowing Conversion − Converts an object to a type that cannot include all of the values of the original type − Example: float to int • Widening Conversion − Converts an object to a type that can include at least approximations to all the values of the original type − Example: int to float • In mixed mode expressions, all numeric types are coerced in expressions using widening conversions • FORTRAN allows mixed mode arithmetic with real and integer data but Pascal does not allow; Ada virtually has no coercions in expressions • In C#, widening conversion is implicit; Java allows widening conversion using type casting • Explicit type conversions are called as casts (type casting) − Example in Java: (int) speed /* Initially, speed is of float type */ Imperative Languages Relational and Boolean Expressions • C, C++, and Java have over 40 operators and at least 15 different levels of precedence • C does not have boolean data type Imperative Languages 45 Input/Output • FORTRAN uses READ and WRITE statements. There is no Stream I/O. − READ(5,10) A,I − 10 FORMAT(F5.3, I3) • Where 5 in READ statement indicates the input device and 10 in READ statement indicates the FORMAT statement • F & I indicates the format of input as floating point and integer respectively. The numbers 5.3 and 3 in FORMAT statement indicate the number of digits used for representation. • Concept of Stream I/O is used in Pascal. − Input is viewed as a long stream of values that can occur virtually anywhere in terms of spacing. − Main concept of input is that it be ordered so that the appropriate values show up for assignment to the corresponding input variables Imperative Languages 46 Short-Circuit Evaluation • While evaluating an expression, evaluation is stopped in the middle as further evaluation won't change the value of the expression • Ada programmers should choose one style (either full evaluation or short circuit) for an entire program, using the other style (not chosen style) only if necessary • Languages like C, C++, C# and Java use short-circuit evaluation for the usual Boolean operators (&& and ||), but also provide bitwise Boolean operators that are not short circuited (& and |). Imperative Languages 47 Assignment Statement 48 • Different symbols are used − Fortran, Basic, PL/I, C, C++ and Java use = − Algol, Pascal and Ada use := • Different assignments: − In Perl, multiple target assignments can be done using • ($a, $b) = (12, 13); − In C, C++, C# and Java, conditional target setting can be done using • total = (first == true) ? total : subtotal; • If the condition (first == true) is true, then expression1 (total = total) is evaluated. Else, expression2 (total = subtotal) will be evaluated. − Compound assignment operators are present in C, C++, C# and Java as • sum += next; − Unary assignment operators are present in C, C++, C# and Java as • b++; Imperative Languages Control Statements • Different types: − Selection statements like if, switch. − Iterative statements like for, while, foreach. − Unconditional branching like goto. • Control Flow − Composition: • Execution is done one statement after another in sequence • Statements can be grouped as compound statements − begin … end OR { … } − Selection or Alternation or Conditional Statements • Only one of the given alternatives is evaluated − Iteration • Repeated few times without any condition • Repeat only if the condition is satisfied Imperative Languages 49 Control Statements − Iteration • Repeating based on a counter. Counter is incremented or decremented • Repeat based on data availability • Indefinite repetition: while true − Selection • Choose between two or more paths • Two-way selectors: if … then … else − Fortran: IF (boolean_expr) statement − The major drawback with this IF statement is that only one statement could be selected. If we need more statements, we need to use GOTO statement. • Nested Selectors: if … if … else − To which if does the else belongs to. − C or Java: else is connected to the nearest if Imperative Languages 50 Control Statements − Selection • Multiple-way selectors − FORTRAN IF: IF (arithmetic exp) N1, N2, N3 • N1 is exp is –ve; N2 if exp is zero; N3 if exp is +ve − FORTRAN has different GOTOs: • Unconditional GOTO: GOTO n • Computed GOTO: Based on a result of an expression • Assigned GOTO: if ( x .gt. y) assign 6 to Label − Case statement • Type of exp allowed • Segments can be single or compound statement • Only one construct is evaluated during any execution or flow through • Is there an else or default or otherwise clause. • Switch in C, C++ and Java: Use of break is important Imperative Languages 51 Control Statements • Example in C prints both “case zero” and “case one” − int i = 0; − switch (i) { • case 0: printf("case zero"); • case 1: printf("case one"); − } • In C#, absence of break or goto in the case statement will generate a compilation error. • Iteration Statements − Function calling itself is called as recursion − Recursion must include a terminal condition, otherwise the program will not stop Imperative Languages 52 Control Statements • Fibonacci in C language • • • • • • • • • • • • • • #include <stdio.h> int fibonacci(int number) { if (number == 0) return 0; if (number == 1) return 1; return fibonacci(number-1) + fibonacci(number-2); } int main(void) { int i; for (i=0; i <= 10; i++) printf("%d ",fibonacci(i)); return 0; } Imperative Languages 53 Control Statements • Counter controlled loops − Type and scope of the loop variable. − Value of loop variable at loop termination. − Changing the loop variable within the loop body and its impact on the loop control. − Evaluation of loop parameters is done only during the first iteration or during all iterations. − Status of loop execution if the lower bound is greater than the upper bound. • FORTRAN 90: − DO label var = start, finish [, stepsize] − Loop variable must be an integer − Loop variable cannot be changed within the loop but start and finish can be changed. − Change of loop parameters will not impact as they are evaluated only once Imperative Languages 54 Control Statements • Pascal − − − − for variable := initial (to | downto) final do statement Loop variable must be an ordinal type of unusual scope After termination, loop variable is considered undefined Loop variables cannot be changed in the loop but loop parameters can be changed. − Changing loop parameters will have no impact. • C language − − − − for ([expr_1] ; [expr_2] ; [expr_3]) statement Absence of expr_2 will make the loop infinite Anything can be changed in the loop First exp is evaluated only once but others are evaluated during each iteration • C++ language: Same as C language. C# and Java has a condition that the control expression must be Boolean Imperative Languages 55 Control Statements • // Variable type should be specified before the for loop in C • for (int i = 0; i < 5; i++) // Allowed in C++ but not in C • // Java wants second part (condition) to be Boolean type • for(i = 0; i = 5; i++) // Valid in C but not in Java and C# • Logically-Controlled loops − − − − − − − Based on pre-test or post-test Pascal has pre-test and post-test: while-do, repeat-until C, C++ has pre-test and post-test : while-do, do-while Java and C# are similar to C or C++ but with Boolean condition Java has no GOTO; C# has goto Ada has pre-test but no post-test Perl has 2 pre-test loops but no post-test: while, until Imperative Languages 56 Control Statements • User-located loop control mechanism − Based on user located statements, using labels. − Example in Ada • • • • • • • • • LOOP1: while … loop … LOOP2: for ... loop ... exit LOOP1 when .. ... end loop LOOP2;... end loop LOOP1; • Break in C, C++ and Java − Break is applied only to a single level − Java has break statement with label also − continue statement is used to skip the remainder of the current iteration and proceed for next iteration • FORTRAN 90 has EXIT (like break) and CYCLE (like continue). Imperative Languages 57 Control Statements • Iteration based on data structures − Iteration is based on the number of elements present in the data structure • C language: for (p=hdr; p; p=next(p)) { ... } • C# language: − int[] group = new int[]{1,2,3}; − foreach (int item in group) System.Console.WriteLine(b); • Perl language: foreach $name (@names) { print $name } • Unconditional branching − − − − Not available in all languages Causes irregular execution sequence and so called spaghetti code Java does not posses unconditional branching statement Pascal and FORTRAN allows label with GOTO statement to be unsigned int constants. C# has goto with label. − Algol 60 and C has label as identifiers. Imperative Languages 58 Control Statements • Long Jump in C language − C language has setjmp and longjmp functions that could provide complex flow of control − setjmp() saves the contents of the registers and longjmp() retrieves those contents. Register contents include those of stack pointer, frame pointer and program counter. Imperative Languages 59 Control Statements • Guarded commands − Some indication to indicate the end of the structure − Guarded commands in Selection statements: Usage of fi • if … fi − Guarded commands in loop statements: Usage of od • do … od • Verification of the program − Presence of unconditional branching makes verification difficult − Guarded statements can help the verification process and presence of selection and logical pre-test loops can make the verification feasible Imperative Languages 60 Stack and Subprograms • Structure of run-time memory − Java uses heap only but C++ class objects can be allocated in static storage, stack or heap. − C# uses both heap and stack depending on what and how things are stored − Stack has top-of-stack pointer that indicates the first available empty position of the stack Imperative Languages 61 Stack and Subprograms 62 • Local non-static variables are stored in the stack as part of the activation record instance or stack frame • Activation record is related to a subprogram call in the sense that it indicates the return address, parameters and automatic local variables • Closure is a pair consisting of the pointer to the subprogram code and a pointer to the activation record • In a subprogram, the formal parameter is the dummy variable used within the subprogram and present in the header of the subprogram. Actual parameters are those used in the subprogram call statement and represent the value or address • Subprogram has a single entry point. The caller is suspended during the subprogram execution. When a subprogram execution terminates control returns back to the caller. Imperative Languages Stack and Subprograms • Semantics of a subprogram call is: − − − − Execution status of the caller is saved. Parameter passing process is carried out. Pass the return address to the callee. Transfer control to the callee. • Subprogram definition: Description of the action of the subprogram abstraction. • Subprogram call: Explicit request to the subprogram that should be executed. • Subprogram header: First line of the subprogram definition that includes the name of the subprogram and their formal parameters. • Parameter profile: Type, number and order of the parameters. • Protocol: Protocol of a subprogram indicates the parameter profile plus the return type. • Subprogram declaration: Provides the protocol but not the body of the subprogram. Imperative Languages 63 Stack and Subprograms • Matching actual and formal parameters can be positional or keyword based − Positional is matched based on the order of parameters − Keyword is based on formal parameter names • SORT(LIST => X, LENGTH => N); • Stack-dynamic: − Can help recursion by storing the values when the subprogram is to be executed and storage is freed when subprogram exists • Keeping local variables static makes sure the data is not lost from the stack • FORTRAN 77 and 90 supports static storage. • C language uses stack-dynamic by default when static reserved word is used, storage is made as static • Pascal, Java and Ada support dynamic storage only Imperative Languages 64 Stack and Subprograms • In C#, reference types like class, interface, delegate, object and string which are inherited from System.Object are stored on the heap. One exception to this is the generic object of System.Object. • In C#, value types like bool, byte, char, int, long, float, etc which come from System.ValueType are allocated based on where they are declared. A value type part of an object will be allocated in the heap Imperative Languages 65 Parameter Passing Methods • Parameter passing − Input or output or both − Passed as a copy or as an access path with pointer (reference) • Pass by value (in mode) − Called as pass by copy − Data is passed as copy (extra space is required) or via reference (write protection is needed if the data not be changed by subprogram) − Pass by constant value: Value is passed as a constant and so cannot be changed • Pass by result (out mode) − Return the local value of called program to caller − Physical move is mostly used − Return value depends on which formal parameter is matched to the actual parameter Imperative Languages 66 Parameter Passing Methods • Pass by value result (inout mode) − Double copying is done for both input and output − Drawbacks include those of pass by result and pass by value • Pass by reference (inout mode) − − − − Called as pass by sharing Uses access path to share values Might be slower due to the use of access path Actual parameter collisions • Mapping different values to same parameter • For Example, void fun (int &a, int &b) { } • Calling the function: fun(x, x); Imperative Languages 67 Parameter Passing Methods • Pass by reference (inout mode) − Array element collisions • // if i is not equal to j, then they refer to different elements. • // They are considered differently in the function and so ok. • fun(a[i], a[j]); • // if i and j are same, then they refer to the same element. • // At the function, they are considered different and so a mismatch. • Also, fun(a, a[i]); − Type checking in C language: − int i = 5; float j = 5.0; − void proc(int a[]) { printf("%d\n",a[0]); } − int main() { proc(&i); /* pointer to an integer */ − // pointer to floating point -- warning incompatible pointer type − proc(&j); return 0; } − Passing floating point to integer array gives compilation warning Imperative Languages 68 Parameter Passing Methods • Pass by name (inout mode) − Parameters are passed by textual substitution of the actual parameter for the corresponding formal parameter − Actual binding of the value or address takes place at the time of variable reference or assignment. This late binding provides flexibility − Not used widely • C Language uses pass by value and pass by reference with pointers. • C++ language uses pass by value, pass by reference with pointers and pass by reference with references. • Java handles parameters like C++ but without references. • Perl supports only pass by reference with references Imperative Languages 69 Parameter Passing Methods • Modern languages implement parameter passing mechanisms using the run-time stack, which is initialized and maintained by run-time system Imperative Languages 70 Parameter Passing Methods • In languages like C and C++, programmer is required to include the size of all the subscripts of the array except the first subscript, in the actual parameter − • Semantics of the subprogram is as below: − − − − • void fun (int matrix [][10]); While using pass by value result parameter passing, move the current values of those parameters to their corresponding actual parameters. While passing a function, move the functional value to a place from which the caller can get it. Restore the execution status of the caller. Transfer control back to the caller. Design of Parameter Passing − − One way or two way; Whether parameters are type checked? What is the correct referencing environment for a subprogram that was sent as a parameter? Imperative Languages 71 Parameter Passing Methods 72 • Earlier version of Pascal and FORTRAN 77 do not type check the parameters but later versions of Pascal and FORTRAN 90 do. • Ada does not allow subprogram parameters. • Java also does not allow method names to be passed as parameters. • C and C++ allow programmers to pass pointers to functions and does type check on the parameters. • Visibility in referencing environment is referred to as shallow binding or deep binding or ad hoc binding • Referencing environment of a subprogram (sub2) using shallow binding includes the subprogram (sub4) that has called this subprogram (sub2), which was sent as parameter. • Deep binding includes only the declaration scope and thus referencing environment of the subprogram (sub2) includes subprogram (sub1), where the subprogram (sub2) is declared. Imperative Languages Parameter Passing Methods • • • • • • 73 Start Sub1 − Start Sub2 … End Sub2 − Start Sub3 Call Sub4(Sub2) End Sub3 − Start Sub4(Subx) Call Subx End Sub4 − Call Sub3 End Sub1 Ad hoc binding includes the subprogram that passed the subprogram (sub2) as a parameter. Ad hoc binding was never used. For static-scoped languages, using deep binding is more natural. Similarly, for dynamic-scoped languages, using shallow binding is more natural Shallow binding: Here, Sub2 is invoked by Sub4 and Sub4 is invoked from Sub3 and Sub3 is invoked from Sub1. − Sub2, Sub4, Sub3, Sub1 Deep binding: Here, Sub2 is declared in Sub1. − Sub2, Sub1 Imperative Languages Parameter Passing Methods • • 74 Overloaded subprograms − Overloaded subprogram is one that has the same name as another subprogram in the same referencing environment − C++, Java, C# and Ada have inbuilt overloaded programs − Generic or polymorphic Subprograms are those subprograms that take different types of parameters at different activations − ad hoc polymorphism: two or more subprograms exist with the same name but with different parameters. − Subtype polymorphism uses the subtype related between types to have many possible types Separate and independent compilation − Independent compilation is the process of compilation of some of the units of a program separately from others and thus not including the benefit of interfaces. Ex. FORTRAN II to FORTRAN 77 − Separate compilation is the process of compilation of some of the units of a program separately from others but with using interface information to check the correctness of the interface between the two parts. Ex. Fortran 90, Ada, C++, C# and Java − Pascal supports neither of them Imperative Languages Parameter Passing Methods • Returning of values from functions − − − − • Ada allows any type to be returned but does not consider subprograms as a type Fortran and Pascal allow only simple types to be returned from a function. C allows any type except functions and arrays as a return type from the function. C++, C# and Java work similar to C language but also allow objects to be returned Accessing Non-Local environments − − FORTRAN COMMON blocks • Common block can contain any number of variables of any type. If a subprogram needs any variable from them, the whole block should be declared • common / name / list-of-variables Static scoping: Using static global variables Imperative Languages 75 Parameter Passing Methods • Accessing Non-Local environments − External declarations as in C language • #include "header.h" // user defined header file • extern void proc(int i); • int main() { proc(100); return 0;} • // header.h file • void proc(int f) { printf("Value = %d\n",f); } Imperative Languages 76 Parameter Passing Methods • External Modules − − Modules are provided using public interface Can be accessed using: import in Java, using in C++ or C# • Dynamic Scope: References to non-static variables could be handled using dynamic scope • User-defined overloaded operators − • Ada and C++ permits user-defined overloaded operators but Java does not. Coroutines (Called as Symmetric Control) − − − − Subprogram with multiple entry points Coroutine call is named as resume Coroutines can be used in concurrent processing To perform coroutine, goto is needed in modern languages Imperative Languages 77 Parameter Passing Methods • #include <stdio.h> • int coroutine1(void) { static int i, state = 0, sum = 0; • switch (state) { − − • 78 Output: Result = 10 CASE 1 Result = 10 case 0: for (i = 0; i < 5; i++) { sum = sum + i; } • state = 1; // states becomes 1 • return sum; case 1: printf("CASE 1"); return sum; } } int main() { int result; result = coroutine1(); printf("Result = %d\n", result); result = coroutine1(); printf("Result = %d\n", result); return 0; } Resume from Main Program Coroutine A1 . . Resume A2 Coroutine A2 . . Resume from Main Program Resume A1 . . . . Resume A2 Resume A1 . . . . Imperative Languages Coroutine A2 Coroutine A1 . . Resume A2 . . . . . First Resume Subsequent Resume . . Resume A1 . . . . Parameter Passing Methods • Implementing Subprograms − • While implementing subprograms, we need to store the status information of the caller, parameters or arguments, return address, functional value (if it is a function), static and dynamic links. This storage is called activation record Testing on our programs − − − − Pascal: free Pascal compiler (open source compiler available from http://www.freepascal.org) on Windows platform. • Compile: fpc.exe filename.pas Run: filename C and C++: gcc and g++ compiler. On Windows platform, gcc and g++ compilers can be used with cygwin. • Compile C programs: gcc filename.c Run: a.out or a.exe C#: Sharp Develop version 2.2.1. Java: use SDK. We have used JEE 5 SDK because we were developing many other Java related programs in Java. Imperative Languages 79