05._Semantic_Analysis

05._Semantic_Analysis - Semantic Analysis Teodor...

Info iconThis preview shows page 1. Sign up to view the full content.

View Full Document Right Arrow Icon
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: Semantic Analysis Teodor Przymusinski, UCR Compiler Construction CS152 Based on the slides by Leonidas Fegaras, UTA get next char source file Type Checking lexer get token token parser AST type checking symbol table Adorned AST type errors 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 checked at compile time Symbol table used to remember declarations 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.) Needs to capture nested scopes: { int a; { bool a; a = true; }; a = 2; }; Interface: void insert ( String key, Object binding ) Object lookup ( String key ) begin_scope () Symbol Table (cont.) class SymbolCell { String name; Declaration binding; SymbolCell next; SymbolCell ( String n, Ast v, SymbolCell r ) { name=n; binding=v; next=r; } } public class SymbolTable { final int symbol_table_size = 1000; 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; } Symbol Table (cont.) int hash ( String s ) { return Math.abs(s.hashCode()); } public void insert ( String key, Declaration binding ) { int loc = hash(key); symbol_table[loc] = new SymbolCell(key, binding, symbol_table[loc]); scope_stack[scope_stack_top++] = loc; } public Declaration lookup ( String key ) { int loc = hash(key); for (SymbolCell s = symbol_table[loc]; s != null; s=s.next) Symbol Table (cont.) public void begin_scope () { scope_stack[scope_stack_top++] = 1; } public void end_scope () { int i = scope_stack_top1; 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; { bool a; a = true; }; a = 2; }; push(-1) insert the binding a:int at the front of table[12] push(12) push(-1) insert the binding a:bool at the front of table[12 push(12) pop() remove the head of table[12] list pop() pop() remove the head of table[12] list pop() hash("a")=12 Declarations The symbol table must contain type declarations (i.e. 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; } } 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 FunctionDeclaration extends Declaration { public Type result; public TypeList parameters; public FunctionDeclaration ( Type t, TypeList tl ) { result=t; parameters=tl; } } class TypeList { public Type head; public TypeList next; public TypeList ( Type h, TypeList n ) { head=h; next=n; } } Types A type-checker is a function that maps an AST node that represents an expression into its type. Uses the type data structures, e.g.: abstract class Type { } class IntegerType extends Type { IntegerType () {} } class IdentifierType extends Type { public String name; public IdentifierType ( String n ) { value=n; } } class IntArrayType extends Type { public Type element; public IntArrayType ( Type et ) { element=et; } } Types 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; } } Type-Checking A tree traversal that checks each node of the AST tree: 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"); Type-Checking (Cont.) } 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"); ... } Type-Checking (Cont.) } 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; } Type-Checking (Cont.) 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 ...
View Full Document

Ask a homework question - tutors are online