View
36
Download
0
Category
Preview:
DESCRIPTION
Semantic Analysis (Symbol Table and Type Checking). Chapter 5. The Compiler So Far. Lexical analysis Detects inputs with illegal tokens Parsing Detects inputs with ill-formed parse trees Semantic analysis (contextual Analysis) Catches all remaining errors. What ’ s Wrong?. Example 1 - PowerPoint PPT Presentation
Citation preview
2
The Compiler So Far
• Lexical analysis– Detects inputs with illegal tokens
• Parsing– Detects inputs with ill-formed parse trees
• Semantic analysis (contextual Analysis)– Catches all remaining errors
4
Why a Separate Semantic Analysis?
• Parsing cannot catch some errors
• Some language constructs are not context-free– Example: All used variables must have been declared
(i.e. in scope)– ex: { int x { .. { .. x ..} ..} ..}– Example: A method must be invoked with arguments
of proper type (i.e. typing)– ex: int f(int, int) {…} called by f(‘a’, 2.3, 1)
5
More problems require semantic analysis
1. Is x a scalar, an array, or a function?2. Is x declared before it is used? 3. Is x defined before it is used?4. Are any names declared but not used?5. Which declaration of x does this reference?6. Is an expression type-consistent?7. Does the dimension of a reference match the
declaration?8. Where can x be stored? (heap, stack, . . . )9. Does *p reference the result of a malloc()?10. Is an array reference in bounds?11. Does function foo produce a constant value?
6
Why is semantic analysis hard?
• need non-local information• answers depend on values, not on syntax• answers may involve computation
7
Symbol Tables
• Symbol Tables Environments– Mapping IDs to Types and Locations– Definitions Insert in the table– Use Lookup ID
• Scope– Where the IDs are “visible”
Ex: formal parameters, local variables in MiniJava
-> inside the method where defined
-- (private) variables in a class
-> inside the class
-- (public) method : visible anywhere (unless overridden)
8
Environments
• A set of bindings ( -> )Initial Env 0
Class C {
int a; int b; int c;
Env = 0 + {a -> int, b -> int, c -> int}
public void m() {
System.out.println(a+c);
int j = a+b;
Env = 1 + {j -> int}
String a = “hello”;
Env = 2 + {a -> String}
System.out.println(a);
9
Environments (Cont’d)
Env = 2 + {a -> String}
System.out.println(a);
System.out.println(a);
System.out.println(a);
}
Env
}
Env
10
Implementing Environments
• Functional Style– Keep previous env and create new one– When restored, discard new one and back to old
• Imperative Style– Destructive update the env(symbol tables)– Undo : need “undo stack”
11
Multiple Symbol Tables : ML-style
structure M = sturct
structure E = struct
val a = 5
end +
structure N = struct
val b = 10
val a = E.a + b
end +
structure D = struct
val d = E.a + N.a
end
End
Initial Env 0
= {a -> int}
= {E -> }
= {b -> int,a -> int}
= {N -> }
= {d -> int}
= {D -> }
=
12
Multiple Symbol Tables : Java-style
Package M;
class E {
static int a = 5;
}
class N {
static int b = 10
static int a = E.a + b
}
class D {
static int d = E.a+ N.a
}
End
Initial Env 0
= {a -> int}
= {E -> }
= {b -> int,a -> int}
= {N -> }
= {d -> int}
= {D -> }
=
13
Implementation – Imperative Symbol Table(inefficient nondestructive update)
a
b
d
c
See Appel Program 5.2 (p106)
Update
Undo
’d
Using a Hash Table
14
Implementation – Functional Symbol Table
• Efficient Functional Approach’a
would return [a
• If implemented with a Hashtable would have to create O(n) buckets for each scope
• Is this a good idea?
15
Implementation - Tree
dog 3
bat 1
dog 3
camel 2
emu 42
m1
m2
m1 = { bat |-> 1 , camel |-> 2, dog |-> 3 }
m2 = {m1 + emu |-> 42 }
How could this be implemented?
Want m2 from m1 in O(n)
16
Symbols v.s Strings as table key
• Symbol:– a wrapper for Stirngs
• Symbol Representation– Comparing symbols for equality is fast.– Extracting an integer hash key is fast.– Comparing two symbols for “greater-than” is fast.
• Properties:– Symbol s1,s2 => – s1 == s2 iff s1.equals(s2) iff s1.string == s2.string
• public class Symbol { public String toString(); public static Symbol getSymbol(String n);}
17
symbol.Symbolpublic class Symbol { public String name; // Symbol cannot be constructed directly private Symbol(String n) { name = n;} public String toString(){ return name; }
private static Map map = new Hashtable();
public static Symbol getSymbol(String n){ // or symbol(..) in book String u = n.intern(); Symbol s = (Symbol) map.get(u); if (s == null){ s = new Symbol(u); map.put(u,s); } return s; } }
18
Symbol Table Implementastion(efficient destructive update)
a
a
b
b
Using a Hash Table
c
c
c
top: Symbol
marker: Binder
null
c
c
null
19
Some sample program(I)
/** * The Table class is similar to
java.util.Dictionary, * except that each key must be a Symbol and there is * a scope mechanism. */
public class Table {
private java.util.Dictionary dict = new java.util.Hashtable(); private Symbol top; private Binder marks;
public Table(){}
20
Some sample program(II)/** * Gets the object associated with the specified * symbol in the Table. */ public Object get(Symbol key) {
Binder e = (Binder)dict.get(key);if (e==null) return null;else return e.value;
}
/** * Puts the specified value into the Table, * bound to the specified Symbol. */ public void put(Symbol key, Object value) {
dict.put(key, new Binder(value, top, (Binder)dict.get(key)));
top = key; }
21
Some sample program(III) /** * Remembers the current state of the Table. */ public void beginScope() {marks = new Binder(null,top,marks); top=null;}
/** * Restores the table to what it was at the most recent * beginScope that has not already been ended. */ public void endScope() {
while (top!=null) { Binder e = (Binder)dict.get(top); if (e.tail!=null) dict.put(top,e.tail); else dict.remove(top); top = e.prevtop;}top=marks.prevtop;marks=marks.tail;
}
22
Some sample program(IV)
package Symbol;
class Binder {
Object value;
Symbol prevtop;
Binder tail;
Binder(Object v, Symbol p, Binder t) {
value=v; prevtop=p; tail=t;
}
}
23
Type-Checking in MiniJava
• Binding for type-checking in MiniJava– Variable and formal parameter
• Var name <-> type of variable
– Method• Method name <-> result type, parameters( including position
information), local variables
– Class• Class name <-> variables, method declaration, parent class
24
Symbol Table: example
See Figure 5.7 on page 111
• Primitive types– int -> IntegerType()– Boolean -> BooleanType()
• Other types– Int [] -> IntArrayType()– Class -> IdentifierType(String s)
25
A MiniJava Program and its symbol table(Figure 5.7)
class B { C f; int[] j; int q;
public int start(int p, int q) { int ret; int a; /* … */ return ret; }
public boolean stop(int p) { /* …*/ return false; } }
class{ C /* …*/ }
B
C
FIELDS
f C
j int[]
g int
METHODS
start int
stop boolean
PARAMS
p int
q int
LOCALS
ret int
a int
PARAMS
p int
LOCALS
….
26
SymbolTable : Real Story
class SymbolTable { public SymbolTable();
public boolean addClass(String id, String parent); public Class getClass(String id); public boolean containsClass(String id);
public Type getVarType(Method m, Class c, String id);
public Method getMethod(String id, String classScope); public Type getMethodType(String id, String classScope);
public boolean compareTypes(Type t1, Type t2);}
27
Be careful!
• getVarType(Method m, Class c, String id)– In c.m, find variable id– Precedence:– Local variable in method– Parameter in parameter list– Variable in the class– Variable in the parent class
• getMethod(), getMethodType()– May be defined in the parent Classes
• compareTypes()– Primitive types : int, boolean, IntArrayType– Subtype : IdentifierType
28
SymbolTalbe : Classclass Class { public Class(String id, String parent); public String getId(); public Type type(); public String parent();
public boolean addMethod(String id, Type type); public Method getMethod(String id); public boolean containsMethod(String id);
public boolean addVar(String id, Type type); public Variable getVar(String id); public boolean containsVar(String id); }
29
SymbolTable : Variable
class Variable{
public Variable(String id, Type type);
public String id();
public Type type()
}
30
SymbolTable : Methodclass Method { public Method(String id, Type type);
public String getId(); public Type type();
public boolean addParam(String id, Type type); public Variable getParamAt(int i); public Variable getParam(String id); public boolean containsParam(String id);
public boolean addVar(String id, Type type); public Variable getVar(String id); public boolean containsVar(String id);}
31
Type-Checking : Two Phases • Build Symbol Table• Type-check statements and expressions
public class Main { public static void main(String [] args) { try { Program root = new
MiniJavaParser(System.in).Program();BuildSymbolTableVisitor v1 = new BuildSymbolTableVisitor();
v1.visit(root);
new TypeCheckVisitor(v1.getSymTab()).visit(root); } catch (ParseException e) { System.out.println(e.toString()); } }}
32
BuildSymbolTableVisitor();
• See Program 5.8 on Page 112
public class BuildSymbolTableVisitor extends TypeDepthFirstVisitor {
…. private Class currClass; private Method currMethod;…… // Type t; // Identifier i; public Type visit(VarDecl n) { Type t = visit(n.t); String id = n.i.toString();
33
BuildSymbolTableVisitor(); - Cont’d
if (currMethod == null){ if (!currClass.addVar(id,t)){ error.complain(id + "is already defined in "
+ currClass.getId()); }
} else { if (!currMethod.addVar(id,t)){ error.complain(id + "is already defined in "
+ currClass.getId() + "." + currMethod.getId());
} } return null;}
34
BuildSymbolTableVisitor() :TypeVisitor()
public Type visit(MainClass n); public Type visit(ClassDeclSimple n); public Type visit(ClassDeclExtends n); public Type visit(VarDecl n); public Type visit(MethodDecl n); public Type visit(Formal n); public Type visit(IntArrayType n); public Type visit(BooleanType n); public Type visit(IntegerType n); public Type visit(IdentifierType n);
35
TypeCheckVisitor(SymbolTable);
• See Program 5.9 on page 113
package visitor;import syntaxtree.*;
public class TypeCheckVisitor extends DepthFirstVisitor {
static Class currClass; static Method currMethod; static SymbolTable symbolTable; public TypeCheckVisitor(SymbolTable s){
symbolTable = s; }
36
TypeCheckVisitor(SymbolTable); - Cont’d
// Identifier i;// Exp e;public void visit(Assign n) { Type t1 =
symbolTable.getVarType(currMethod,currClass, n.i.toString()); Type t2 = n.e.accept( new TypeCheckExpVisitor(symbolTable) ); if (symbolTable.compareTypes(t1,t2)==false){
error.complain("Type error in assignment to " +n.i.toString());
}}
37
TypeCheckExpVisitor(SymbolTable)
package visitor;import syntaxtree.*;
public class TypeCheckExpVisitor extends TypeDepthFirstVisitor {
// Exp e1,e2; public Type visit(Plus n) { if (! (n.e1.accept(this) instanceof IntegerType) ) { error.complain("Left side of Plus must be of type
integer"); } if (! (n.e2.accept(this) instanceof IntegerType) ) { error.complain("Right side of Plus must be of type
integer"); } return new IntegerType(); }
38
TypeCheckVisitor : Visitor()
public void visit(MainClass n);
public void visit(ClassDeclSimple n);
public void visit(ClassDeclExtends n);
public void visit(MethodDecl n);
public void visit(If n);
public void visit(While n);
public void visit(Print n);
public void visit(Assign n);
public void visit(ArrayAssign n);
39
TypeCheckExpVisitor() : TypeVisitor()
public Type visit(And n); // boolean public Type visit(LessThan n); // boolean public Type visit(Plus n); // int public Type visit(Minus n); public Type visit(Times n); public Type visit(ArrayLookup n); // int public Type visit(ArrayLength n); // int public Type visit(Call n); // result type public Type visit(IntegerLiteral n); // int public Type visit(True n); // boolean public Type visit(False n); public Type visit(IdentifierExp n); // symbol table lookup public Type visit(This n); // current class public Type visit(NewArray n); // int[] public Type visit(NewObject n); // public Type visit(Not n); // boolean
40
Overloading of Operators, ….
• When operators are overloaded, the compiler must explicitly generate the code for the type conversion.– 2 + 2 2.0 + 3.4 2.4 + 4 – “abc” + 4
• For an assignment statement, both sides have the same type. When we allow extension of classes, the right hand side is a subtype of lhs.– long x = (int) y + 3– Person p = new Student();
41
Method Calls e.m(…)
• Lookup method in the SymbolTable to get parameter list and result type
• Find m in class e• The parameter types must be matched against the actual
arguments.• Result type becomes the type of the method call as a
whole.
• Etc, etc, …….
42
TypeChecking method call
// Exp e; Identifier i; ExpList el; public Type visit(Call n) { Type rcvType = visit(n.e); if(!(receiverType instanceof IdentifierType)) error.complain(…); Method m = symbolTable.getMethod( n.i.toString(), rcvType.toString());
if(n.el.size() != m.getParamSize()) error.complain(…) for ( int i = 0; i < n.el.size(); i++ ) { Type acType = visit(n.el.get(i)); Type fmType = m.getParam(i); if(!symbolTable.compareType(acType,fmType)) error.complain(…) ; } return m.type(); }
43
Error Handling
• For a type error or an undeclared identifier, it should print an error message.
• And must go on…..
• Recovery from type errors?– Do as if it were correct.– Not a big deal in our homework.
• Example:– int i = new C();– int j = i + 1;– still need to insert i into symbol table as an integer so the rest can
be typechecked..
Recommended