Homework 3 Semantic Analysis Remi Meier Compiler Design 28.10.2015 1
Compiler phases Javali Compiler x86 Assembly IR IR Front-end Optimizations Back-end Machine independent Machine dependent Lexical Analysis Syntactic Analysis AST Semantic Analysis 2
Homework 3 Class class Main { void main() { write(true); writeln(); Text HW 2 Write Method Seq WriteLn HW 3 ERROR BoolConst Abstract Syntax Tree How do we check a program for mistakes that are difficult / impossible to catch with grammar rules?
Semantic Analysis Text Lexer Parser AST syntactically correct Semantic Analysis AST enriched, correct Input Syntactically well-formed AST Output Enriched AST with types and other semantic information Warnings: warn programmer about possible mistakes Error messages: ensure correctness for later compiler stages Two parts: 1) Collect information (enrich AST) 2) Check for correctness of the AST 4
What information? We use the following terms: Names are words in the program text Symbols are semantic entities storing information about names class Main { int foo; int main() { int bar; write(bar); Main int foo int main int bar write bar field foo in of class Main type int of var bar inherits in returns in class Object method main 5
Symbol table Keep information about symbols in symbol table: mapping: name symbol central repository of information hierarchical structure through lexical scoping Lexical scoping: class A { void main() { class B extends A { Javali scopes: Global: all class symbols, built-in types Class: members and super-class members Method: parameters and local variables 6
Scoping rules class A { void main() { Javali scopes: global, class, method class B extends A { Rules: within a scope: symbols have unique names inner scopes hide symbols of outer scopes But: separate namespace for types separate namespace for methods 7
Scoping rules: example class foo { foo foo; void foo() { int foo; void bar() { class bar extends foo { foo foo; void bar() { foo(); bar(); Types / Classes separate namespace e.g.: int, class foo, class bar (Inherited) Methods separate namespace can be overridden through inheritance e.g.: bar() (Inherited) Fields same namespace as local variables and parameters can be hidden by local variable / parameter e.g.: foo.foo can be shadowed through inheritance e.g.: bar.foo 8
Implementation Symbol VariableSymbol Param, Local, Field MethodSymbol Method declarations TypeSymbol PrimitiveTypeSymbol int, boolean, void ArrayTypeSymbol Foo[] ClassSymbol Class declarations Hints: Create symbols for every: class, method, parameter, local variable, array type, field, Object, null, and primitive types Enrich AST with symbols 9
Implementation No need for a single symbol table link tables to reflect scopes: e.g., a symbol table per method symbol collect as much information as you need in whatever way you want Use visitors to collect information to check for correctness second step 10
Check for correctness Look at list of checks in homework description throw SemanticFailure on detected error class Test { void m() { write(1); class A extends B { class B extends A { INVALID_START_POINT: no Main or main() CIRCULAR_INHERITANCE class Main { void main() { int a, a; DOUBLE_DECLARATION 11
Check for correctness int m() { if (true) { return 0; void m() { int a; boolean b; a = a + b; MISSING_RETURN TYPE_ERROR 12
Demo 13
Notes Some checks can be performed while collecting information Visitors are your friends In general, you cannot statically ensure correctness of a program Due date is Nov, 12 th. Start early! 14
Design Patterns 15
Task 1: Tree traversal In-order 0 Preorder 0 1 2 1 2 3 4 5 3 4 5 6 6 Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. 16
Iterator pattern interface TreeIterator { Node getcurrent(); boolean hasnext(); void next(); PreOrderTreeIterator TreeIterator InOrderTreeIterator it = new InOrderTreeIterator(tree) while (it.hasnext()) { it.next(); it.getcurrent() common foreach (Node n : tree) { 17
Task 2: Printing strategies 0 Decimal 3, 1, 4, 0, 2, 6, 5 1 2 Binary 11, 1, 100, 0, 10, 110, 111 3 4 5 6 Define a family of algorithms, encapsulate each one, and make them interchangeable. 18
Strategy pattern interface PrintingStrategy { String printnode(node n); BinaryPrinter PrintingStrategy DecimalPrinter PrintingStrategy strategy; if (isbinary) strategy = new BinaryPrinter(); else strategy = new DecimalPrinter(); Strategy selection foreach (Node n : tree) { strategy.printnode(n); Iteration over tree Composition of patterns: Data Structure + + Iterator Strategy 19
Task 3: Tree observer 0 NodeObserver 1 2 3 4 +1 5 ChangeLogger ChangeLogger ChangeLogger 6 +1 interface NodeObserver { void update(node n); Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. 20
Observer pattern 0 1 2 addobserver() 0 1 2 3 4 5 3 4 5 6 6 setvalue() notifyobservers(this) void notifyobservers(node n) { for (NodeObserver obs : observers) { obs.update(n); if (getparent()!= null) getparent().notifyobservers(n); 21