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

Semantic Analysis (Symbol Table and Type Checking)

Embed Size (px)

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

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