1 / 19

Semantic Analysis

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

lorrainef
Download Presentation

Semantic Analysis

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Leonidas Fegaras Semantic Analysis

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

  3. 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)‏

  4. 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 ()‏

  5. 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; }

  6. 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; }

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

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

  9. 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; } }

  10. 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; } }

  11. 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];

  12. 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; } }

  13. 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; } }

  14. 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");

  15. 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"); ... }

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

  17. 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); }

  18. 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); }

  19. 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);

More Related