1 / 15

Compiler Design 18. Object Oriented Semantic Analysis (Symbol Tables, Type Checking)

Kanat Bolazar March 30, 2010. Compiler Design 18. Object Oriented Semantic Analysis (Symbol Tables, Type Checking). Object-Oriented Symbol Tables and Type Checking. In object-oriented languages, scope changes can occur at a finer-grained level than just block or procedure definition

jaron
Télécharger la présentation

Compiler Design 18. Object Oriented Semantic Analysis (Symbol Tables, Type Checking)

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. Kanat Bolazar March 30, 2010 Compiler Design18. Object Oriented Semantic Analysis(Symbol Tables, Type Checking)

  2. Object-OrientedSymbol Tables and Type Checking • In object-oriented languages, scope changes can occur at a finer-grained level than just block or procedure definition • Each class has its own scope • Variables may be declared at any time • Notation to represent symbol tables as a combination of environments An environment maps an identifier to its symbol table entry, which we only give the type here for brevity: e1 = { g → string, a → int } • We will indicate adding to the symbol table with a +, but this addition will carry the meaning of scope (from right to left): e2 = e1 + { a → float }means to look an identifer up in the rightmost environment first and if not found, continue looking to the left

  3. Example Scope in Java • Note: All examples in these slides are from Andrew Appel "Modern Compiler Implementation in Java" (available online through SU library) (environment e0 already given for predefined identifiers) e1 = e0 + { a → int, b → int, c → int} e2 = e1 + { j → int} e3 = e2 + { a → string} e1 e0 1 class C { 2 int a, b, c; 3 public void m ( ) { 4 System.out.println(a + c) 5 int j = a + b; 6 String a = ‘hello’; 7 System.out.println(a); 8 System.out.println(j); 9 System.out.println(b); 10 } 11 }

  4. Each Class Has An Environment • There may be several active environments at once (multiple symbol tables) • Class names are mapped to environments (each one added to environment e0): e1 = { a → int } e2 = { E→ e1 } e3 = { b → int, a → int} e4 = { N→ e3 } e5 = { d → int } e6 = { D→ e5 } e7 = e2 + e4 + e6 Classes E, N and D are all compiled in environment e7: M → e7 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; }

  5. Symbol Table • Each variable and formal parameter name has a type • Each method name has its signature • Each class name has its variable and method declarations class B { C f; int[] j; int q; public int start (int p, int q) { int ret, a; /* . . . */ return ret; } public boolean stop (int p) { /* . . . */ return false; } } B C Fields: f C j int[] q int Methods: start int stop bool Params: p int q int Locals: ret int a int Params: p int Locals:

  6. Typechecking Rules • Additional rules include • The new keyword: C e = new C ( ) • Gives type C to e (as usual) • Method calls of the form e.m ( <paramlist>) • Suppose e has type C • Look up definition of m in class C • Appel recommends the two-pass semantic analysis strategy • First pass adds identifiers to the symbol table • Second pass looks up identifiers and does the typechecking

  7. Example of Inheritance • Note variables in scope of await definition: passengers, position, v, this • In c.await(t), in the body of wait, v.move will be the move method from Truck class Vehicle { int pos; // position of Vehicle void move (int x) { pos += x; } } class Car extends Vehicle { int passengers; void await(Vehicle v) { // if ahead, ask other to catch up if (v.pos < pos) v.move(pos – v.pos); // if behind, catch up with +10 moves else this.move(10); } } class Truck extends Vehicle { void move(int x) { // max move: +55 if (x <= 55) pos += x; } } class Main { public static void main(…) { Truck t = new Truck(); Car c = new Car(); Vehicle v = c; c.passengers = 2; c.move(60); v.move(70); c.await(t); } }

  8. Single Inheritance of Data Fields (Locations) • To generate code for v.position, the compiler must generate code to fetch the field position from the object that v points to • v may actually be a Car or Truck • Prefixing fields: • When B extends A, the fields of B that are inherited from A are laid out in a record at the beginning in the order they appear. • Fields not inherited are laid out in order afterwards All children of A have field a as field[0] class A { int a = 0;} class B extends A { int b = 0; int c = 0;} class C extends A {int d = 0;} class D extends B { int e = 0; } A a B a b c C a d D a b c e

  9. Single Inheritance for Methods (Locations) • A method instance is compiled into code that resides at a particular address. In semantic analysis phase: • Each variable’s symbol table entry has a pointer to its class descriptor • Each class descriptor contains a pointer to its parent class and a list of method instances • Each method instance has a location • Static methods: method call of the form c.f ( ) • the code for a method declared as static depends on the type of the variable c and not the type of the object that c holds • Get the class of c, call it C • in Java syntax, the method call is C.f ( ), making this clear • Search class C for method f • If not found, search the parent for f, then its parent and so on • When f is found, possibly in some ancestor class A, then the method call for c.f will be compiled to the method instance of A.

  10. Single Inheritance for Dynamic Methods • Dynamic method lookup needs class descriptors • may be overridden is a subclass • To execute c.f(), the compiled code must execute instructions: • Fetch the class descriptor d at from object c at offset 0 • Fetch the method-instance pointer p from the f offset of d • Call p Instances of A, B, C, D and D class A { int x = 0; int f () { … } } class B extends A { int g () { … } } class C extends B { int g () { … } } class D extends C { int y = 0; int f () { … } } x x x x y x y A B C D A_f A_f B_g A_f C_g D_f C_g descriptors Notation: A_f is an instance of method f declared in class A

  11. Multiple Inheritance • In languages that permit multiple inheritance, a class can extend several different parent classes • Cannot put all fields of all parents in every class • Analyze all classes to assign one offset location for every field name that can be used in every record with that field • Use graph coloring algorithm, but still has large numbers of offsets with sparse use of offset numbers class A { int a = 0; } class B { int b = 0; int c = 0; } class C { int d = 0; } class D extends A, B, C { int e = 0; } A a B b c C a d D a b c d e

  12. Multiple Inheritance Solutions • After graph coloring, assign offset locations and give a sparse representation that keeps which fields are in each record • Leads to another level in accessing fields and methods • Fetch the class descriptor d at from object c • Fetch the field-offset value from the descriptor • Fetch the method or data from the appropriate offset of d • The coloring of fields is done at link time, can still have problems with dynamic linking, where a new class can be loaded at run-time • Solved with hash tables of field names and access algorithms with additional overhead

  13. Type Coercions • Given a variable c of type C, it is always legal to treat c as if it were any supertype of c • If C extends B, and b has type B, then assignment “b = c;” is safe • Reverse is not true. Assignment “c = b;” is safe only if b is really (at run-time) an instance of C. • Safe object-oriented languages (Modula-3 and Java) will add to any coercion from a superclass to a subclass, a run-time typecheck that raises an exception unless b really is an instance of C. • C++ is unsafe in this respect. It allows a static cast mechanism. The dynamic cast mechanism does add the run-time checking.

  14. Private Fields and Methods • In the symbol table for every class C, for all the fields and methods, keep a flag to indicate whether that method or field is private. • When type checking c.v or c.f ( )the compiler will check the symbol table flag and must use the context (i.e. whether the compiler is inside the declaration of the object) to decide whether to allow the access • This is another example of inherited attributes for the typechecking system • Additional flags can be kept for access at the subclass or package level • And additional context must be kept by the typechecking algorithm

  15. Main Reference • Slides were prepared by Nancy McCracken, using examples from: • Andrew Appel, Modern Compiler Implementation in Java, second edition, Cambridge University Press, 2002. • Available at SU library as an online resource, viewable when you log in to SU library. • You can read the whole book, chapter by chapter, but not download as PDF.

More Related