Names and scopes

advertisement
Names, Scopes and Bindings
Aaron Bloomfield
CS 415
Fall 20051
1
Binding
• A binding is an association between two things,
such as a name and the thing it represents
• Example: int x
– When this statement is compiled, x is bound to a
memory space
2
Binding Time
• The time at which the association between two
items is created
• There are many different binding times that can
be implemented:
–
–
–
–
–
–
–
Language design time
Language implementation time
Program writing time
Compile time
Link time
Load time
Run time
3
Binding Times
• Language design time
– These are control flow constructs, primitives, and
other semantics
– Think of reserved words: i.e. if, for, else, while, etc.
• Language implementation time
– These include I/O couplings
– System dependent things such as max heap and
stack sizes
– Think of constants: MAX_INT, etc.
– In Algol, this included the I/O procedure names
4
Binding Times
• Program writing time
– When you the programmer choose data structures
and names
• Compile time
– The compiler maps high level constructs to machine
code
– Think of the assembly for a compiled procedure
• Link time
– Separate compilation means not every part of a
program has to be compiled at the same time
– Libraries are linked to your program and bound
5
Binding Times
• Load time
– For primitive operating systems
– Binds physical addresses
– Most OSes do this during link time with virtual
addresses
• Run time
– Very broad term covering the span of execution
– Values to variable bindings occur here
6
Binding Times
• Very important to design and implementation of
programming languages
– Early bindings = greater efficiency
– Later bindings = greater flexibility
7
Scope rules
• The textual region of the program in which a
binding is active is its scope
• Static scoping is more common in modern
programming langauges
– Found in C, C++, Pascal
8
Static scope
• All scoping can be determined at compile time
• Most often this is done with a textual top-tobottom scan
• Most basic static scope rule: everything has
global scope
9
Fortran Implementation
• Global scopes
• Local scopes limited to their subroutines
• Local variable scope extends through the
execution of the subroutine unless the variable
is saved
10
Nested Subroutines
• Introduced in Algol 60 and is found in some
modern languages
– Pascal, Ada
• Subroutines can be declared inside other
subroutines
– This confuses the scope rules even more
11
Closest Nested Scope Rule
• A variable declared has its scope in the current
subroutine,
and
any
internally
nested
subroutines, unless there is a definition with the
same name more locally
12
Closest Nested Scope Rule
Example
procedure level1()
variable x;
procedure level2()
variable x;
begin
(* level 2 code *)
end
begin
(* level 1 code *)
end
procedure outside()
begin
(*outside code*)
end
13
Dynamic Scope Rules
• Generally less complicated to implement
• The “current” binding for a name is the one most
recently encountered during execution, and not
yet destroyed by returning from its scope
• APL, Snobol, early dialects of Lisp, and Perl
have dynamic scoping
14
Implications
• Semantic rules are dynamic rather than static
– Type checking is generally deferred until run time
• To accommodate these rules, dynamically
scoped languages are most often interpreted
• Very easy for an interpreter to look up the
meaning of a name
– All that is needed is a stack of declarations
• However, it makes it harder to understand
programs
– The modern consensus seems to be that dynamic
scoping is usually a bad idea
15
Dynamic scope example
int print_base = 10;
print_integer (int n) {
switch (print_base) {
case 10: ...
case 8: ...
case 16: ...
case 2: ...
}
}
foo {
print_integer (10);
int print_base = 16;
print_integer (10);
print_base = 2;
print_integer (4);
}
16
Alternatives to achieve the same
result
• Overloading and optional parameters
– print_integer takes an optional parameter (one with a
default value) that specifies the base
– print_integer is overloaded: one form prints in
decimal, the other form takes an additional parameter
that specifies the base
• Better or worse than dynamic scoping?
17
More implications
• With dynamic scoping, no program fragment that
makes use of non-local names is guaranteed a
predictable referencing environment
18
19
Referencing Environments
• A referencing environment is the complete set of
bindings in effect at a given point in a program
• Static scope rules:
– Referencing environment
nesting of program blocks
dependent
on
lexical
• Dynamic scope rules:
– Referencing environment dependent on the order in
which declarations are reached
20
What about references to
functions?
• When are dynamic scope rules applied?
– When the function is called?
• Shallow binding
– When the reference is created?
• Deep binding
21
int max_score;
float scale_score (int raw_score) {
return (float) raw_score / (float) max_score;
}
float highest_score (int[] scores, function_ptr scaling_function) {
float max_score = 0;
foreach score in scores {
float percent = scaling_function (score);
if ( percent > max_score )
max_score = percent;
function is called
}
return max_score;
}
main() {
reference is created
max_score = 50;
int[] scores = ...
print highest_score (scores, scale_score);
}
22
Deep Binding
• Generally the
languages
default
in
lexically
scoped
• Dynamically scoped languages tend to use
shallow binding
23
Implementing Deep Binding
• Subroutine Closure
24
The Symbol Table
• During compilation, keeps track of all the
identifiers
• Only matters in a statically scoped language!
– Why?
• Basic functions: lookup() and insert()
• Must keep track of scope as well
– Often by enter_scope() and leave_scope() functions
25
Activation records
• When a subroutine starts, a number of things
have to be stored:
–
–
–
–
A copy of the parameters (pass by value)
The return address when the subroutine exits
Local variables in the subroutine
Etc.
• This data is called the activation record
• Fortran (up until 90) only had space for one
activation record
– Thus, you couldn’t call more than one subroutine at a
time
26
Recursive vs. Iterative
• Ocaml will recognize tail recursion and convert it
to a while loop:
let foo x = if x = 0 then 0 else 1 + foo (x-1);;
• A call to foo 1000000 would require one million
activation records if called recursively
– That’s many, many megs of memory!
– In addition to the time spent creating them and
branching to the next recursive call of the subroutine
• An iterative solution avoids all that
– Although there is still the branch for the loop
27
Lifetimes
Lifetime = time from creation to deletion
• Bindings
• Objects
28
Storage Management
• Static - absolute address, retained throughout
program
• Stack - LIFO, subroutine calls
• Heap – allocation/deallocation at arbitrary times
29
Heap Management
• Free list
30
Who Manages the Heap?
• User
• System
31
Garbage Collection
• Mark and Sweep
• Reference Counting
32
Aliases
33
Download