5 Symbol Table 5 1 5 2 5
5. Symbol Table 5. 1 5. 2 5. 3 5. 4 5. 5 Overview Symbols Scopes Types Universe 1
Responsibilities of the Symbol Table 1. It stores all declared names and their attributes • • • type value (for constants) address (for local variables and method arguments) parameters (for methods). . . 2. It is used to retrieve the attributes of a name • Mapping: name (type, value, address, . . . ) 2
Symbol Table as a Linear List Given the following declarations const int n = 10; class T {. . . } int a, b, c; void M () {. . . } we get the following linear list "n" Const "T" Type "a" Field "b" Field "c" Field "M" Meth for every declared name there is a Symbol node + simple + declaration order is retained (important if addresses are assigned only later) - slow if there are many declarations 3
Symbol Table as a Binary Tree Declarations const int n = 10; class T {. . . } int a, b, c; void M () {. . . } Resulting binary tree "M" Meth "T" Type "b" Field "a" Field + fast "c" Field "n" Const - can degenerate unless it is balanced - larger memory consumption - declaration order is lost Only useful if there are many declarations 4
Symbol Table as a Hashtable Declarations const int n = 10; class T {. . . } int a, b, c; void M () {. . . } Resulting hashtable 0 "M" Meth 1 "b" Field 2 "n" Const 3 "c" Field + fast "T" Type "a" Field - more complicated than a linear list - declaration order is lost For our purposes a linear list is sufficient • Every scope is a list of its own anyway • A scope has hardly more than 10 names 5
5. Symbol Table 5. 1 5. 2 5. 3 5. 4 5. 5 Overview Symbols Scopes Types Universe 6
Symbol Nodes Every declared name is stored in a Symbol node Kinds of symbols in Z# • • constants global variables fields method arguments local variables types methods program public enum Kinds { Const, Global, Field, Arg, Local, Type, Meth, Prog } 7
Possible Object-oriented Architecture Possible class hierarchy of objects Symbol name type next Constant val Global Field Argument adr Local adr Type Method n. Args n. Vars locals Program locals Therefore we choose a "flat implementation": all information is stored in a single class. This is ok because • extensibility is not required: we never need to add new object variants • we do not need dynamically bound method calls 8
Class Symbol class Symbol { public enum Kinds { Const, Global, Field, Arg, Local, Type, Meth, Prog } Kinds string Struct Symbol int int Symbol } kind; name; type; next; val; adr; n. Args; n. Locs; locals; // Const: value // Arg, Local: address // Meth: number of arguments // Meth: number of local variables // Meth: parameters & local variables; Prog: symbol table of program 9
Entering Names into the Symbol Table The following method is called whenever a name is declared Symbol sym = Tab. Insert(kind, name, type); • • • creates a new object node with kind, name, type checks if name is already declared (if so => error message) assigns successive addresses to variables and fields enters the declaration level for variables (0 = global, 1 = local) appends the new node to the end of the symbol table list returns the new node to the caller 10
Predeclared Names Which names are predeclared in Z#? • Standard types: int, char • Standard constants: null • Standard methods: ord(ch), chr(i), len(arr) 11
Special Names as Keywords int and char could also be implemented as keywords. requires a special treatment in the grammar Type< Struct type> = ident | "int" | "char". (. Symbol sym = Tab. Find(token. str); type = sym. type; . ) (. type = Tab. int. Type; . ) (. type = Tab. char. Type; . ) 12
5. Symbol Table 5. 1 5. 2 5. 3 5. 4 5. 5 Overview Symbols Scopes Types Universe 13
Scope = Range in which a Name is Valid There are separate scopes (object lists) for • • the "universe" contains the predeclared names (and the program symbol) the program contains global names (= constants, global variables, classes, methods) every method contains local names (= argument and local variables) every classcontains fields "int" "char" . . . "a" "b" "M" "x" "b" "c" "P" outer locals top. Scope • Searching for a name always starts in top. Scope • If not found, the search continues in the next outer scope • Example: search b, a and int 14
Scope Nodes class Scope { Scope outer; Symbol locals; int n. Args; int n. Locs; } // to the next outer scope // to the symbols in this scope // number of arguments in this scope (for address allocation) // number of local variables in this scope (for address allocation) 15
Entering Names in Scope Names are always entered in top. Scope class Tab { Scope top. Scope; // Zeiger auf aktuellen Scope. . . static Symbol Insert (Symbol. Kinds kind, string name, Struct type) { //--- create symbol node Symbol sym = new Symbol(name, kind, type); if (kind == Symbol. Kinds. Arg) sym. adr = top. Scope. n. Args++; else if (kind == Symbol. Kinds. Local) sym. adr = top. Scope. n. Locs++; //--- insert symbol node Symbol cur = top. Scope. locals, last = null; while (cur != null) { if (cur. name == name) Error(name + " declared twice"); last = cur; cur = cur. next; } if (last == null) top. Scope. locals = sym; else last. next = sym; return sym; }. . . } 16
Opening and Closing a Scope Method. Decl = Type< type> ident (. Struct type; . ) global variable (. cur. Method = Tab. insert(Symbol. Kinds. Meth, token. str, type); Tab. Open. Scope(); . ). . . "{". . . "}"(. cur. Method. n. Args = top. Scope. n. Args; cur. Method. n. Locs = top. Scope. n. Locs; cur. Method. locals = Tab. top. Scope. locals; Tab. Close. Scope(); . ). Note • The method name is entered in the method's enclosing scope • Before a scope is closed its local objects are assigned to m. locals • Scopes are also opened and closed for classes 17
Example "int" class P "char" . . . "P" Tab. Open. Scope(); top. Scope 18
Example "int" class P int a, b; { Tab. Insert(. . . , "a", . . . ); Tab. Insert(. . . , "b", . . . ); "a" "char" . . . "P" "b" top. Scope 19
Example class P int a, b; { void M () "int" Tab. Insert(. . . , "M", . . . ); Tab. Open. Scope(); "a" "char" "b" . . . "P" "M" top. Scope 20
Example "int" class P int a, b; { void M () int x, "char" "a" "b" "x" "y" . . . "P" "M" y; Tab. Insert(. . . , "x", . . . ); Tab. Insert(. . . , "y", . . . ); top. Scope 21
Example "int" class P int a, b; { void M () int x, y; {. . . } "a" meth. locals = Tab. top. Scope. locals; Tab. Close. Scope(); top. Scope "char" "b" . . . "P" "M" "x" "y" 22
Example "int" class P int a, b; { void M () int x, y; {. . . } prog. locals = Tab. top. Scope. locals; Tab. Close. Scope(); top. Scope "a" "char" "b" . . . "P" "M" "x" "y" 23
Searching Names in the Symbol Table The following method is called whenever a name is used Symbol sym = Tab. Find(name); 24
5. Symbol Table 5. 1 5. 2 5. 3 5. 4 5. 5 Overview Symbols Scopes Types Universe 25
Types Every object has a type with the following properties • size (in Z# determined by metadata) • structure (fields for classes, element type for arrays, . . . ) 26
Structure Nodes for Primitive Types int a, b; char c; kind name type next val adr n. Args n. Vars locals Local "a" 0 - Local "b" Local "c" 1 - 2 - object node structure node kind elem. Type fields Int - Char - There is just one structure node for int in the whole symbol table. All symbols of type int reference this one. The same is true for structure nodes of type char. 27
Structure Nodes for Arrays int[] a; int b; kind name type next val adr n. Args n. Vars locals Local "a" Local "b" 0 - 1 - kind elem. Type fields Arr - Int - The length of an array is statically unknown. It is stored in the array at run time. 28
Structure Nodes for Classes class C { int x; int y; int z; } C v; kind name type next val adr n. Args n. Vars locals Type "C" Global "v" - Int - kind Class elem. Type fields kind name type next val adr n. Args n. Vars locals Field "x" Field "y" Field "z" - - - 29
Type Compatibility: Name Equivalence Two types are equal if they are represented by the same type node (i. e. if they are denoted by the same type name) class T {. . . } T a; T b; Type "T" Global "a" Global "b" . . Class. . . The types of a and b are the same Name equivalence is used in Java, C/C++/C#, Pascal, . . . , Z# Exception In Java (and Z#) two array types are the same if they have the same element types! 30
Type Compatibility: Structural Equivalence Two types are the same if they have the same structure (i. e. the same fields of the same types, the same element type, . . . ) class T 1 { int a, b; } class T 2 { int c, d; } T 1 x; T 2 y; Type "T 1" Global "x" Type "T 2" Global "y" . . . Class - Class Field "a" Field "b" Field "c" Field "d" . . . Int - The types of x and y are equal (but not in Z#!) Structural equivalence is used in Modula-3 but not in Z# and most other languages! 31
Methods for Checking Type Compatibility class Struct {. . . // checks, if two types are compatible (e. g. in comparisons) public bool Compatible. With (Struct other) { return this. Equals(other) || this == Tab. null. Type && other. Is. Ref. Type() || other == Tab. null. Type && this. Ref. Type(); } // checks, if this can be assigned to dest public bool Assignable. To (Struct dest) { return this. Equals(dest) || } this == Tab. null. Type && dest. Is. Ref. Type() || kind == Kinds. Arr && dest. elem. T necessary for standard function len(arr) // checks, if two types are equal (structural equivalence for array, name equivalence otherwise) public bool Equals (Struct other) { if (kind == Kinds. Arr) return other. kind == Kinds. Arr && elem. Type. Equals(other. elem. Type); return other == this; } public bool Is. Ref. Type() { return kind == Kinds. Class || kind = Kinds. Arr; } } 32
Solving LL(1) Conflicts with the Symbol Table Method syntax in Z# void Foo () int a; { a = 0; . . . } 33
Solving the Conflict With Semantic Information static void Block () { Check(Token. LBRACE); for (; ; ) { if (Next. Token. Is. Type()) Var. Decl(); else if (la First(Statement)) Statement(); else if (la {rbrace, eof}) break; else { Error(". . . "); . . . recover. . . } } Check(Token. RBRACE); } static bool Next. Token. Is. Type() { if (la != ident) return false; Symbol sym = Tab. Find(la. Token. str); return sym. kind == Symbol. Kinds. Type; } Block = "{" { Var. Decl | Statement } "}". 34
5. Symbol Table 5. 1 5. 2 5. 3 5. 4 5. 5 Overview Symbols Scopes Types Universe 35
Structure of the "universe" chr. Sym kind name type val adr n. Args n. Locs locals ord. Sym len. Sym no. Sym Type "int" Type "char" Const "null" Meth "chr" Meth "ord" Meth "len" Const "no. Symbol" - - 0 - 1 - 1 - 0 - Arg "i" Arg "ch" Arg "arr" 0 - 0 - kind elem. Type fields Int - Char - int. Type char. Type Class - null. Type Arr - None - no. Type 36
Interface of the Symbol Table class Tab { static Scope top. Scope; // current top scope static Struct int. Type; // predefined types char. Type; null. Type; no. Type; static Symbol chr. Sym; ord. Sym; len. Sym; no. Sym; // predefined symbols static Symbol Insert (Symbol. Kinds kind, string name, Struct type) {. . . } static Symbol Find (string name) {. . . } static void Open. Scope () {. . . } static void Close. Scope () {. . . } static void Init () {. . . } // builds the universe and initializes Tab } 37
- Slides: 37