Languages and Compilers SProg og Oversttere Bent Thomsen
Languages and Compilers (SProg og Oversættere) Bent Thomsen Department of Computer Science Aalborg University With acknowledgement to Wei-Tek Tsai who’s slides this lecture is based on. 1
Some Issues in language and compiler design • Simple syntax => simple semantics => simplementation • Syntax vs types • Single pass vs multi pass compiler • Use of CC tools vs by-hand • Java. CC, JLex/CUP and Sable. CC • AST as intermediate representation • Visitors pattern 2
Multi Pass Compiler A multi pass compiler makes several passes over the program. The output of a preceding phase is stored in a data structure and used by subsequent phases. Dependency diagram of a typical Multi Pass Compiler: Compiler Driver calls Syntactic Analyzer Contextual Analyzer Code Generator input output Source Text AST Decorated AST Object Code 3
JLex/CUP vs. Sable. CC 4
Java. CC and JJTree 5
Design Patterns • Classes and objects are useful organizing concepts • Culture of design patterns has developed around objectoriented programming – Shows value of OOP for program organization and problem solving 6
What is a design pattern? • General solution that has developed from repeatedly addressing similar problems. • Example: singleton – Restrict programs so that only one instance of a class can be created – Singleton design pattern provides standard solution • Not a class template – Using most patterns will require some thought – Pattern is meant to capture experience in useful form 7
Visitors pattern • Represent operations to be performed on an object structure • Define new operations without changing the classes of the elements on which they operate 8
Motivation • • Compiler represents programs as abstract syntax trees (AST) Need to perform operations on AST for semantic analysis, codegeneration, pretty-printing and so on AST has different types of nodes for variable reference, assignment, operator, etc. Code for an operation is specific to the node type Node Type. Check() Generate. Code() Pretty. Print() Variable. Ref. Node Assignment. Node Type. Check() Generate. Code() Pretty. Print() 9
Motivation (contd. ) • Adding operation code to each node type has the following drawbacks that makes it hard to understand maintain: – Code for each operation is distributed across multiple classes (Assignment. Node, Variable. Ref. Node, etc) – Code for different unrelated operations are mixed together as methods on a single node – Adding a new operation would mean changing and recompiling all the node classes • Better Approach: – Node classes independent of the operations that apply to them – Can be achieved using a visitor design pattern 10
Visitor • Solution using Visitor: – Visitor is an abstract class that has a different method for each type of object on which it operates – Each operation is a subclass of Visitor and overloads the type-specific methods – Objects that are operated on, accept a Visitor and call back their type-specific method passing themselves as operands – Object types are independent of the operations that apply to them – New operations can be added without modifying the object types 11
Visitor Solution Node • Nodes accept visitors and call appropriate method of the visitor • Visitors implement the operations and have one method for each type of node they visit Accept( Node. Visitor v ) Variable. Ref. Node Assignment. Node Accept(Node. Visitor v) {v->Visit. Variable. Ref(this)} Accept(Node. Visitor v) {v->Visit. Assignment(this)} Node. Visitor Visit. Assignment( Assignment. Node ) Visit. Variable. Ref( Variable. Ref. Node ) Type. Checking. Visitor Visit. Assignment( Assignment. Node ) Visit. Variable. Ref( Variable. Ref. Node ) Code. Generating. Visitor Visit. Assignment( Assignment. Node ) Visit. Variable. Ref( Variable. Ref. Node ) 12
Applicability Use the Visitor pattern when: • When an object structure contains different classes of objects with different interfaces and operations on these objects depend on their concrete classes • Many unrelated operations need to be performed on the objects and you want to keep related operations together • The classes defining the object structure rarely change, but you want to define new operations over the structure • If the object structure classes change often, it is better to define the operations in those classes 13
Consequences of using Visitor • Addition of new operations is easy – New operations can be created by simply adding a new visitor • Gathers related operations together – All operation related code is in the visitor – Code for different operations are in different sub-classes of visitor – Unrelated operations are not mixed together in the object classes • Adding a new concrete type in the object structure is hard – Each Visitor has to be recompiled with an appropriate method for the new type 14
Reference • E. Gamma, and others, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994. 15
- Slides: 15