190 likes | 314 Views
Leonidas Fegaras. Semantic Analysis. Type Checking. get next character. Checking whether the use of names is consistent with their declaration in the program int x; x := x+1; correct use of x x.A := 1; x[0] := 0; type errors
E N D
Leonidas Fegaras Semantic Analysis
Type Checking get next character • Checking whether the use of names is consistent with their declaration in the program int x; x := x+1; correct use of x x.A := 1; x[0] := 0; type errors • Statically typed languages: done at compile time, not at run time • Need to remember declarations • Symbol Table get token AST AST scanner source file type checking parser token symbol table type errors
Symbol Table • A compile-time data structure used to map names into declarations • It stores: • for each type name, its type definition • eg. for the C type declaration typedef int* mytype, it maps the name mytype to a data structure that represents the type int* • for each variable name, its type • if the variable is an array, it also stores dimension information • it may also store storage class, offset in activation record, etc • for each constant name, its type and value • for each function and procedure, its formal parameter list and its output type • each formal parameter must have • name • type • type of passing (by-reference, by-value, etc)
Symbol Table (cont.) • Need to capture nested scopes, if necessary { int a; { int a; a = 1; }; a = 2; }; • Interface: void insert ( String key, Object binding ) Object lookup ( String key ) begin_scope () end_scope ()
The Gen Symbol Table class SymbolCell { String name; Ast binding; SymbolCell next; SymbolCell ( String n, Ast v, SymbolCell r ) { name=n; binding=v; next=r; } } public class SymbolTable { final int symbol_table_size = 997; SymbolCell[] symbol_table = new SymbolCell[symbol_table_size]; final int scope_stack_length = 100; int scope_stack_top = 0; int[] scope_stack = new int[scope_stack_length]; public SymbolTable () { scope_stack_top = 0; }
The Gen Symbol Table (cont.) int hash ( String s ) { return Math.abs(s.hashCode()) % symbol_table_size; } public void insert ( String key, Ast binding ) { int loc = hash(key); symbol_table[loc] = new SymbolCell(key,binding,symbol_table[loc]); if (scope_stack_top >= scope_stack_length) fatal_error("stack overflow",new Variable(key)); else scope_stack[scope_stack_top++] = loc; } public Ast lookup ( String key ) { int loc = hash(key); for (SymbolCell s = symbol_table[loc]; s != null; s=s.next) if (s.name.equals(key)) return s.binding; return null; }
The Gen Symbol Table (cont.) public void begin_scope () { if (scope_stack_top >= scope_stack_length) fatal_error("stack overflow",new Number(0)); else scope_stack[scope_stack_top++] = -1; } public void end_scope () { int i = scope_stack_top-1; for (; scope_stack[i]>=0 && i>0; i--) { int loc = scope_stack[i]; symbol_table[loc] = symbol_table[loc].next; }; scope_stack_top = i; }
Example { int a; { int a; a = 1; }; a = 2; }; push(-1) insert the binding a:int at the front of table[12] list push(12) push(-1) insert the binding a:int at the front of table[12] list push(12) pop() remove the head of table[12] list pop() pop() remove the head of table[12] list pop() hash(“a”)=12
Type ASTs • A typechecker is a function that maps an AST that represents an expression into its type • Need to define the data structures for types: abstract class Type { } class IntegerType extends Type { public IntegerType () {} } class BooleanType extends Type { public BooleanType () {} } class NamedType extends Type { public String name; public NamedType ( String n ) { value=n; } } class ArrayType extends Type { public Type element; public ArrayType ( Type et ) { element=et; } }
Type ASTs (cont.) class RecordComponents { public String attribute; public Type type; public RecordComponents next; public RecordComponents ( String a, Type t, RecordComponents el ) { attribute=a; type=t; next=el; } } class RecordType extends Type { public RecordComponents elements; public RecordType ( RecordComponents el ) { elements=el; } }
Declarations • The symbol table must contain type declarations (ie. typedefs),variable declarations, constant declarations, and function signatures: class SymbolCell { String name; Declaration binding; SymbolCell next; SymbolCell ( String n, Declaration v, SymbolCell r ) { name=n; binding=v; next=r; } } Symbol[] symbol_table = new Symbol[SIZE];
Declarations (cont.) abstract class Declaration { } class TypeDeclaration extends Declaration { public Type declaration; public TypeDeclaration ( Type t ) { declaration=t; } } class VariableDeclaration extends Declaration { public Type declaration; public VariableDeclaration ( Type t ) { declaration=t; } } class ConstantDeclaration extends Declaration { public Type declaration; public Exp value; public ConstantDeclaration ( Type t, Exp v ) { declaration=t; value=v; } }
Declarations (cont.) class TypeList { public Type head; public TypeList next; public TypeList ( Type h, TypeList n ) { head=h; next=n; } } class FunctionDeclaration extends Declaration { public Type result; public TypeList parameters; public FunctionDeclaration ( Type t, TypeList tl ) { result=t; parameters=tl; } }
Typechecking • A tree traversals that checks each node of the AST tree recursively: static Type typecheck ( Exp e ) { if (e instanceof IntegerExp) return new IntegerType(); else if (e instanceof TrueExp) return new BooleanType(); else if (e instanceof FalseExp) return new BooleanType(); else if (e instanceof VariableExp) { VariableExp v = (VariableExp) e; Declaration decl = lookup(v.value); if (decl == null) error("undefined variable"); else if (decl instanceof VariableDeclaration) return ((VariableDeclaration) decl).declaration; else error("this name is not a variable name");
Typechecking: BinaryExp } else if (e instanceof BinaryExp) { BinaryExp b = (BinaryExp) e; Type left = typecheck(b.left); Type right = typecheck(b.right); switch ( b.operator ) { case "+": if (left instanceof IntegerType && right instanceof IntegerType) return new IntegerType(); else error("expected integers in addition"); ... }
Typechecking: CallExp } else if (e instanceof CallExp) { CallExp c = (CallExp) e; Declaration decl = lookup(c.name); if (decl == null) error("undefined function"); else if (!(decl instanceof FunctionDeclaration)) error("this name is not a function name"); FunctionDeclaration f = (FunctionDeclaration) decl; TypeList s = f.parameters; for (ExpList r=c.arguments; r!=null && s!=null; r=r.next, s=s.next) if (!equal_types(s.head,typecheck(r.head))) error("wrong type of the argument in function call") if (r != null || s != null) error("wrong number of parameters"); return f.result; } • equal_types(x,y) checks the types x and y for equality • Two types of type equality: type equality based on type name equivalence, or based on structural equivalence
The Calculator Interpreter • Evaluate an expression e using a symbol table st: static double eval ( Tree e, SymbolTable st ) { if (e instanceof LongLeaf) return (double) ((LongLeaf) e).value(); else if (e instanceof DoubleLeaf) return ((DoubleLeaf) e).value(); else if (e instanceof StringLeaf) return error("Strings are not permitted",e); else if (e instanceof VariableLeaf) { Tree s = st.lookup(((VariableLeaf) e).value()); if (s == null) return error("Undefined variable",e); else if (s instanceof DoubleLeaf) return ((DoubleLeaf) s).value(); else return error("Name is not a variable",e); }
The Calculator Interpreter (cont.) else match e { case call_exp(`fnc,...args): double res; Tree s = st.lookup(((VariableLeaf) fnc).value()); if (s == null) return error("Undefined function",fnc); match s { case fnc_def(`body,...params): Trees arguments = #[]; for ( Tree arg: args ) arguments = arguments.append(new DoubleLeaf(eval(arg,st))); if (params.length() != arguments.length()) return error("Wrong number of arguments",e); st.begin_scope(); for ( Tree param: params ) { st.insert(((VariableLeaf) param).value(),arguments.head()); arguments = arguments.tail(); }; res = eval(body); st.end_scope(); return res ; } case _: return error("Name has not been defined as a function",fnc); }
The Calculator Interpreter (cont.) caseif_exp(`e1,`e2,`e3): if (eval(e1,st) > 0) return eval(e2,st); else return eval(e3,st); case `f(`e1,`e2): double left = eval(e1,st); double right = eval(e2,st); match new VariableLeaf(f) { case plus_exp: return left + right; case minus_exp: return left - right; case times_exp: return left * right; case div_exp: return left / right; case and_exp: return ((left>0) && (right>0)) ? 1 : 0; • case or_exp: return ((left>0) || (right>0)) ? 1 : 0; case eq_exp: return (left == right) ? 1 : 0; case ne_exp: return (left != right) ? 1 : 0; case gt_exp: return (left > right) ? 1 : 0; case lt_exp: return (left < right) ? 1 : 0; case ge_exp: return (left >= right) ? 1 : 0; case le_exp: return (left <= right) ? 1 : 0; } } case _: return error("Unrecognized expression",e);