Principles of Programming Languages
h"p://www.di.unipi.it/~andrea/Dida2ca/PLP-16/
- Prof. Andrea Corradini
Department of Computer Science, Pisa
- Sta:c Scoping
Principles of Programming Languages - - PowerPoint PPT Presentation
Principles of Programming Languages h"p://www.di.unipi.it/~andrea/Dida2ca/PLP-16/ Prof. Andrea Corradini Department of Computer Science, Pisa Lesson 19 Sta:c Scoping Declara:ons and Defini:ons Modules Local symbol tables
1) In the whole block where it is defined 2) From the declara:on to the end of the block
a) Only aNer declara:on b) In the scope of declara:on
uses 1–b also for variables!
2
const N = 10; ... procedure foo; const M = N; (* static semantic error! *) var A : array [1..M] of integer; N : real; (* hiding declaration *)
Reported errors: “N used before declara:on” “N is not a constant”
3
struct manager; // Declaration only struct employee { struct manager *boss; struct employee *next_employee; ... }; struct manager { // Definition struct employee *first_employee; ... };
variables are declared in a block
– At the beginning of the block (Pascal, ADA, …) – Anywhere (C/C++, Java, …)
subrou:nes that are called where they are defined
blocks in a single func:on are all stored in the subrou:ne frame for that func:on (most programming languages, e.g. C/C ++, Ada, Java)
{ int t = a; a = b; b = t; } declare t:integer begin t := a; a := b; b := t; end; { int a,b; ... int t; t=a; a=b; b=t; ... }
C Ada C++ Java C#
4
5
hides X in P1
code is executed to inactivate the binding of X to P1
procedure P1; var X:real; procedure P2; var X:integer begin ... (* X of P1 is hidden *) end; begin ... end
6
7
8
9
10
11
12
struct S { int a; int b; } s; void swap(int& a, int& b) { int t; t = a; a = b; b = t; } void somefunc() { … swap(s.a, s.b); … }
13
struct S { int a; int b; } s; void swap(int& a, int& b) { int t; t = a; a = b; b = t; } void somefunc() { … swap(s.a, s.b); … }
(0) (4) a b
(0) (4) (8) a b t
Subroutine frame fp[0]= fp[4]= fp[8]=
14
struct S { int a; int b; } s; void swap(int& a, int& b) { int t; t = a; a = b; b = t; } void foo() { … swap(s.a, s.b); … }
Trec S Tfun swap Tfun foo Tint Tref
a b t prev (0) (4) (8) [12] prev [0] s prev=nil swap foo globals (0) [8] a b prev=nil (0) (4) [8]
15
16
Synthesized attributes: T.type pointer to type (ex.: ‘integer’, array(2, ‘real’), pointer(record(Table)), …) T.width storage width of type (bytes) E.place name of temp holding value of E ProducEons P → D ; S D → D ; D | id : T | proc id ; D ; S T → integer | real | array [ num ] of T | ^ T | record D end S → S ; S | id := E | call id ( A ) Global data to implement scoping: tblptr stack of pointers to tables
stack of offset values ProducEons (cont’d) E → E + E | E * E | - E | ( E ) | id | E ^ | & E | E . id A → A , E | E
17
enter(table, name, type, offset) enterproc(table, name, newtable)
18
19
a Trec b s Tint Tfun swap a b t Tptr prev=nil prev prev=nil prev Tfun foo swap foo globals (0) (0) (4) (8) (0) (4)
[12] [0] [8] [8]
struct S { int a; int b; } s; void swap(int& a, int& b) { int t; t = a; a = b; b = t; } void foo() { … swap(s.a, s.b); … }
20
s x y (0) (8) (12)
Globals
a b t (0) (4) (8)
Subroutine frame fp[0]= fp[4]= fp[8]=
21
22
{ E.place := newtemp();
In the translation just shown, lookup of a name may require traversing all enclosing symbol tables, from the current one to the global one. The LeBlanc & Cook Symbol Table implementation for static scoping uses a hash table and a stack, instead of a tree of symbol tables. This guarantees more efficient lookups.
– Predefined names: 0 (pervasive) – Global names: 1, and so on
– Entries contain symbol name, category, scope number, (pointer to) type, …
– Entries contain scope number and additional info (closed?, …). They are pushed and popped by the semantic analyzer when entering/leaving a scope
the scope number n
– If n <> 0 (not pervasive), scan the Scope Stack to check if scope n is visible – Stops at first closed scope. Imported/Export entries are pointers.
23
24
type T = record F1 : integer; F2 : real; end; var V : T; ... module M; export I; import V; var I : integer; ... procedure P1 (A1 : real; A2t: integer) : real; begin ... end P1; ... procedure P2 (A3 : real); var I : integer; begin ... with V do ... end; ... end P2; ... end M;
type T = record F1 : integer; F2 : real; end; var V : T; ... module M; export I; import V; var I : integer; ... procedure P1 (A1 : real; A2t: integer) : real; begin ... end P1; ... procedure P2 (A3 : real); var I : integer; begin ... with V do ... end; ... end P2; ... end M;
Hash table Scope stack Hash link Name Category Scope Type Other Closed? Other — — — — — — — — — parameters
M
1 2
record V
5 3 1 mod
A1
4 (2) param
P1
3 (1) func
I I I
5 (1) var 3 (1) var export 1 (1) var
A2
4 (1) param
V
3 import var
F2
2 (2) field record scope 2
T
1 type
V
1 var
integer
(1) (2) type
real
type —
F1
2 (1) field
A3
5 (2) — param
P2
proc 3 parameters
with V P2 M
Globals X Scope
[2] [3] [4] [5] [1]
25
procedure lookup(name) pervasive := best := null apply hash function to name to find appropriate chain foreach entry e on chain if e.name = name –– not something else with same hash value if e.scope = 0 pervasive := e else foreach scope s on scope stack, top first if s.scope = e.scope best := e –– closer instance exit inner loop elsif best != null and then s.scope = best.scope exit inner loop –– won’t find better if s.closed exit inner loop –– can’t see farther if best != null while best is an import or export entry best := best.real entry return best elsif pervasive != null return pervasive else return null –– name not found