CSE 3341: Principles of Programming Languages Core Concepts I Jeremy Morris 1
Imperative Language Basics The model of most imperative languages is straightforward: Programs are a sequence of expressions or statements Expressions read values from memory and produce a new value Some expressions may have side effects that change values in memory Statements read values from memory and do not produce new values All statements operate by side effect Assignment statements – most basic example Core idea: Expressions are evaluated, Statements are executed 2
Imperative Language Basics Early languages sought to break away from being machine dependent Assembly languages are machine dependent These language designers sought a higher level of abstraction Separation of function from the details of machine implementation Or separation of function from implementation details period (Sound familiar – it should. Think client vs. implementer) Key to this idea are names Strings of symbols used to refer to "things" in a programming language Variables, procedures, constants, etc. 3
Binding and Binding Time Binding is an association between two things Typically we are using it in reference to binding a name to a target (or object in the textbook's terminology) Binding time is when a binding occurs A few important ones: Compile time Compiler chooses how to bind high-level constructs to machine code Link time When code in libraries are joined together by a linker Load time When the OS loads a program into memory Run time The entire span of execution of a program from beginning to end Static vs. Dynamic Static before run time, dynamic during runtime 4
Object lifetime Lifetime of an object The period of time between when an object is created and when it is destroyed Lifetime of a binding The period of time between when a binding between a name and an object is created and when it is destroyed Object lifetimes generally fall into one of three types based on how they are allocated Static objects Stack objects Heap objects 5
Static Allocation An absolute memory location retained through the program's execution Typically global variables Also (in some languages) variables that are local to a subroutine but retain value from one invocation to the next Numeric and string-valued constant literals The lifetime of a statically allocated variable is the entire program Local variables are not typically statically allocated in modern languages If a language doesn't have recursion, local variables can be statically allocated Fortran as originally designed, for example Recursion means we need to do something else Stack allocation can help us solve this problem 6
Static local variable in C void adder() { static int x = 0; x++; printf("%d\n", x); } int main(int argc, char *argv[]) { adder(); // prints 1 adder(); // prints 2 adder(); // prints 3 return 0; } 7 Example courtesy Wikipedia: https://en.wikipedia.org/wiki/Static_variable
Stack Allocation Image courtesy Programming Language Pragmatics p. 118 8
Heap Allocation The heap is free memory allocated to the program by the OS The programmer can allocate it however they want Uses keywords like new (Java/C++) or malloc (C) to allocate memory from the heap for the program Uses keywords like delete (C++) or free (C) to free it up Data in the heap is accessed via references (or pointers) Addresses in the heap to where data is stored new and malloc both return a reference (pointer) to the memory they allocate The lifetime of a heap allocated object is controlled by the programmer May be as long or as short as the programmer needs 9
C program running in memory 10 Example courtesy Wikipedia: https://en.wikipedia.org/wiki/Data_segment
Scope The region in the code where a binding is active is its scope Scope can be determined statically or dynamically Almost all modern languages have static scoping Dynamic scoping comes with a run-time cost Static scoping is also known as lexical scoping Because we can determine it from the code at compile time Just by reading the source, we can understand the scope of every variable Dynamic scoping can only be determined at run-time 11
Static/Lexical Scope Probably what you think of when you think of scope Java, C, C++, Python, Pascal … Most modern languages use lexical scope Typically the current binding between a name and a target is based on the "block" of code that the name appears in Scope can often be nested – variables in outer blocks can be accessed from within inner blocks (but not vice-versa) 12
Static/Lexical Scope – Java Example public class Sample { private static int avg = 33; private static int average( int[] list) { int x = avg; int avg = 0; for ( int i=0; i<list.length; i++) { int y = list[i]; avg += y; } if (list.length > 0) { avg /= list.length; } return avg; } public static void main(String[] args) { int[] list = { 2, 4, 6, 8, 10 }; int avg = average(list); System.out.println("The average is: " + avg); } } 13
Static/Lexical Scope – C++ Example int avg = 33; double average( int list[], int size) { double x = avg; double avg = 0; for ( int i=0; i<size; i++) { int x = list[i]; avg += x; } if (size > 0) { avg /= size; } return avg; } int main(String[] args) { int list[5] = { 2, 4, 6, 8, 10 }; double avg = average(list); cout << "The average is: " << avg << endl; return 0; } 14
Static/Lexical Scope – Python Example avg = 33 def average(list): avg = 0 for x in list: avg += x if ( len(list) > 0 ): avg /= len(list) return avg def foo(): local = 10 def bar(): local = 5 print ("Local2: "+str(local)) bar() print ("Local1: "+str(local)) print ("The average is: "+str(avg)) list = [2,4,6,8,10] avg = average(list) print ("The average is: "+str(avg)) 15
Static/Lexical Scope – C/C++ In Java, you can refer to methods before you declare them Scope is the entire block they are declared in In C/C++, you cannot Scope is only after they've been declared This is a problem for recursive types and subroutines How can you refer to something if it isn't in scope? C/C++ solve this problem by separating declaration from definition Only declaration has to exist before you can use it Definition can come after you've used it 16
Static/Lexical Scope – C/C++ bool isEven( int x); bool isOdd( int y); bool isEven(int x) { if (x == 0) { return true; } else { return isOdd(x-1);} } bool isOdd( int x) { if (x == 0) { return false; } else { return isEven(x-1);} } 17
Dynamic scope Bindings between names and targets can only be determined at run-time Depending on the flow of control of the program, bindings may be different You can't tell from reading the code exactly what the scope of a variable is It will depend on what was previously executed before the code reached that point If you are used to static scoping, this idea may seem very odd 18
Dynamic scope example int n void first(): n = 1 void second(): int n first() main(): n = 2 int x = readInteger() if (x > 0) then second() else first() println (n) 19 Example courtesy Michael Scott – Programming Language Pragmatics
Scope implementation Scope rules in a compiler are implemented using the symbol table If everything is global, it's just a mapping of symbols to internal keys Think about the recursive descent algorithm discussed in class Scope rules require some extra complexity Augment the symbol table with "enter scope" and "leave scope" operations to keep track of visibility Nothing is ever deleted from a symbol table – even when it falls out of scope It's just marked "out of scope" Retained through entire compilation Scope rules in an interpreter are treated in a similar fashion Interpreter also has to keep track of the targets tied to each binding 20
Expression Evaluation An expression is a line of code that is evaluated and produces a result Expressions can be combinations of operands and operators An operator in a language is a built-in function that uses special syntax An operand is one of the arguments to the operator function 3 + 2, x + y, x++, --j, etc. Expressions can also be function calls Typically the name in parentheses with arguments in parentheses myFunction(x,y) In some languages, operands are just syntactic sugar for function calls Ada – "+"(a,b) C++ - a.operator+(b) Scala – a.+(b) 21
Expression Values & Assignment Variables are a binding between a memory location and a value Semantics of how we read the variable differ Sometimes the variable designates a value x * 3 multiply the value stored in x by 3 But sometimes it designates a memory location x = 3 store the value three in the memory location denoted by x Value model of variables "l-value" denotes a memory location "r-value" denotes a value But … pointers/references can make this tricky 22
Recommend
More recommend