Semantic Analysis (Symbol Table and Type Checking)

43
1 Semantic Analysis (Symbol Table and Type Checking) Chapter 5

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

Transcript of Semantic Analysis (Symbol Table and Type Checking)

1

Semantic Analysis(Symbol Table and Type Checking)

Chapter 5

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

3

What’s Wrong?

• Example 1 int y = x + 3;

• Example 2

String y = “abc” ;

y ++ ;

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..