Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
Compiler ConstructionComputations on ASTs
Lennart Andersson
Revision 2011-02-07
2011
Compiler Construction 2011 F06-1
Hand-coded parser without actions
void stmt() {switch(token) {case IF:accept(IF); expr(); accept(THEN); stmt();break;
case ID:accept(ID); accept(EQ); expr();break;
default:error();
}}
Compiler Construction 2011 F06-2
Hand-coded parser with semantic actions
Stmt stmt() {switch(token.kind) {case IF:accept(IF);Expr e = expr();accept(THEN);Stmt s = stmt();return new IfStmt(e, s);
case ID:IdExpr id = new IdExpr(token.image);accept(ID);accept(EQ);Expr e = expr();return new Assignment(id, e);
}}
Compiler Construction 2011 F06-3
.jj file with actions
Stmt stmt() : {Stmt s;}{
(s = ifStmt() | s = assignment()) {return s;}}IfStmt ifStmt() : {Expr e; Stmt s;}{
"if" e = expr() "then" s = stmt(){return new IfStmt(e, s);}
}Assignment assignment() : {Token t; Expr e;}{
t = <ID> "=" e = expr(){return new Assignment(new IdExpr(t.image), e);}
}
Compiler Construction 2011 F06-4
Building trees with JJTree
I jjtree is a preprocessor to javacc using a .jjt file
I grammar productions with tree building directives ”#. . . ”
I jjtree generates a .jj file with tree building actions
I builds a parse tree by default (Assignment 2)
I with option NODE DEFAULT VOID=true building requires #directives
Compiler Construction 2011 F06-5
jjtree stack
jjtree has a stack for collecting the children of a node. It is easy to
I build a node corresponding to a nonterminal
I ignore building a node for a terminal/nonterminal
I build List and Opt nodes
I build “left recursive” trees when the grammar is right recursive
I build trees when the grammar has common prefixes
Compiler Construction 2011 F06-6
Building an AST node for a nonterminal
Add a # directive to the corresponding AST class
void ifStmt() #IfStmt : { } {<IF> expr() <THEN> stmt() <FI>
}
IfStmt: Stmt ::= Expr Stmt
I the current top of stack is marked
I expr() pushes an Expr node
I stmt() pushes a Stmt node
I a new IfStmt node is created
I the nodes above the mark will be popped and
I become children of the IfStmt node
I this node will be pushed on the stack
Compiler Construction 2011 F06-7
Skipping nodes
A terminal or nonterminal without a # directive will be skipped
void ifStmt(): { } {<IF> expr() <THEN> stmt() <FI>
}
I expr() pushes an Expr node if it has a # directive
I no node is pushed for THEN
I stmt() pushes a Stmt node if it has a # directive
I no nodes will be popped by this production
I no IfStmt is created
I this is probably an error
Compiler Construction 2011 F06-8
Building a token node
IdExpr: Expr ::= <ID:String>;
void idExpr() #IdExpr : {Token t;}{
t = <ID>{jjtThis.setID(t.image);}
}
I jjtThis refers to the new IdExpr node
I the setID(String) method has been generated by jastadd
Compiler Construction 2011 F06-9
Building a List node
void program() #Program : {}{
"begin" ([stmt() (";" stmt())*]) #List(true) "end"}Program ::= Stmt*;
I a marker for Program is put on the stackI "begin" is parsed without pushing anythingI a marker for List is put on the stackI a node is pushed on the stack for each stmtI the parser reaches #List(true) and all nodes above the List
marker are popped and become children of a new List nodeI this node is pushed on the stackI the "end" token is acceptedI the only node above the Program mark is popped an becomes
the child of a new Program nodeI this node is pushed on the stack
Compiler Construction 2011 F06-10
Why #List(true)?I the List will be built even it is emptyI with #List(false) nothing will be build for an empty listI with jastadd empty trees must be generated
Program
List
Stmt Stmt...
0 or more
Compiler Construction 2011 F06-11
Optional node
void classDecl() #ClassDecl : { }"class" classId() (["extends" classId()]) #Opt(true)ClassBody()
I an Opt node will be built even if there is no extends clauseI with jastadd empty Opt nodes must be generated
ClassDecl
OptClassId ClassBody
...may be empty
Compiler Construction 2011 F06-12
Building left-recursive trees with jjtree
abstract Expr;BinExpr: Expr ::= Left:Expr Right:Expr;Mul: BinExpr;Div: BinExpr;
void expr() : { }{
factor()( "*" factor() #Mul(2)| "/" factor() #Div(2))*
}
I #Mul(2) builds a Mul node
I pops two nodes from the stack
I and turns them into children
I pushes the new Mul node to the stack
Compiler Construction 2011 F06-13
Returning the AST to the client
Creating and using the parser
Parser parser = new Parser(...);Start start = parser.start();
jjtree specification
Start start() #Start : { }{
expr();{return jjtThis;}
}
jjtThis refers to the Start node created by start()
Compiler Construction 2011 F06-14
Semantic analysis
scannersource code
tokens
parser
AST builder
parse tree
AST
semanticanalysis
AST with attributes
codegeneration
Compiler Construction 2011 F06-15
Examples of computations
I Name analysis: find the declaration of an identifier
I Type analysis: compute the type of an expression
I Expression evaluation: compute the value of a constantexpression
I Code generation: compute an intermediate coderepresentation of a program
I Unparsing: compute a text representation of a program
Compiler Construction 2011 F06-16
An expression evaluator
Abstract grammar
abstract Expr;abstract BinExpr : Expr ::= Left:Expr Right:Expr;Add : BinExpr;Sub : BinExpr;IntExpr : Expr ::= <INT:String>;
Compiler Construction 2011 F06-17
Evaluator implementation
abstract class Expr {abstract int value();
}abstract class BinExpr extends Expr { }class Add extends BinExpr {
}class Sub extends BinExpr {
}class IntExpr extends Expr {
}Compiler Construction 2011 F06-18
An unparser
abstract Stmt;IfStmt : Stmt ::= Cond:Expr Then:Stmt [Else:Stmt];
abstract class Stmt {abstract void unparse(PrintStream s, String indent);
}class IfStmt extends Stmt {
void unparse(PrintStream s, String indent) {s.print(indent);s.print("if ");getCond().unparse(s, indent);s.println(" then ");getThen().unparse(s, indent + " ");if (hasElse()) {
s.println(" else ");getElse().unparse(s, indent + " ");
}}
}Compiler Construction 2011 F06-20
The Interpreter design pattern
Intent
Given a language, define a representation for its grammaralong with an interpreter that uses the representation tointerpret sentences in the language.
Example
“Computer” in the OMD course (eda061)
Compiler Construction 2011 F06-21
Interpreter pattern
Expressioninterpret(Context)
TerminalExpressioninterpret(Context)
NonTerminalExpressioninterpret(Context)
*
Compiler Construction 2011 F06-22
Example applications
The expression evaluator
I value() plays the role of the interpret method
I no Context was needed (but would be needed if we had alanguage with identifiers)
I Expr plays the role of the abstract Expression
I IntExpr plays the role of TerminalExpression
I Add and Sub play the role of NonTerminalExpression
The unparser
I unparse() plays the role of the interpret method
I Context consists of two parameters: (PrintStream s, Stringindent)
I Stmt and Expr play the role of abstract Expressions
I IfStmt plays the role of NonTerminalExpression
I . . .
Compiler Construction 2011 F06-23
Count the number of identifiers
Abstract grammar
abstract Stmt;IfStmt : Stmt ::= Cond:Expr Then:Stmt [Else:Stmt];...abstract Expr;abstract BinExpr : Expr ::= Left:Expr Right:Expr;Add : BinExpr;Sub : BinExpr;IntExpr : Expr ::= <INT:String>;IdExpr : Expr ::= <ID:String>;...
Compiler Construction 2011 F06-24
Implementation of the counter
class ASTNode {int countIds() {int count = 0;for (int k = 0; k < getNumChild(); k++)
count += getChild(k).countIds();return count;
}}class IdExp extends Expr {
int countIds() {return 1;}
}
Compiler Construction 2011 F06-25
The Composite design pattern
Intent
Compose objects into tree structures to representpart-whole hierarchies. Composite lets clients treatindividual objects and compositions of objects uniformly.
Example
Any recursive data type.
Compiler Construction 2011 F06-26
The Composite design pattern
Componentoperation(Context)
Leafoperation(Context)
Nodeoperation(Context)
* children
for all g in childreng.operation(context)
Compiler Construction 2011 F06-27
Example applications
The counter
I countIds() plays the role of the operation method
I ASTNode plays the role of Component
I IdExp plays the role of Leaf
I Other classes play the role of Node. Rather thanimplementing count() in each of these classes, they inherit adefault implementation of ASTNode.
Other typical applications
I Graphical objects that can be grouped hierarchically
I Line, Rectangle, Text, etc. play the role of Leaf
I Group plays the role of Node
I paint(Graphics) plays the role of an operation method
Compiler Construction 2011 F06-28
Modularization
How can new functionality be added to the AST classes?
I methods, instance variables, ...
Modify the AST classes?
I not modular
I risky to modify generated code— what happens if we need to regenerate the AST classes?
Modular techniques
I Intertype declarations (Static Aspect-Oriented Programming)
I Visitor pattern
Compiler Construction 2011 F06-29
Aspect-Oriented Programming“Cross-cutting concerns”
I One aspect concerns many classes
I The aspect cross-cuts the normal language constructs andleads to tangled code
AOP techniques
I aspect constructs can modularize cross-cutting code, therebyavoiding tangled code
I A special kind of compiler, an aspect weaver, weaves togetheraspect code and ordinary code during compilation AOPsystems
AOP systems
I AspectJ, http://www.eclipse.org/aspectj/, (from XeroxPARC)
I Hyper/J, http://www.research.ibm.com/hyperspace/ (IBM)
I AOSD homepage: http://aosd.net
Compiler Construction 2011 F06-30
Example of Tangled CodeImplementation of expression evaluator and unparser
abstract class Expr {abstract int value();abstract void unparse(Stream s, String indent);
}abstract class BinExpr extends Expr {
Expr getLeft() { ... }Expr getRight() { ... }
}class Add extends BinExpr {
int value() { ... }void unparse(Stream s, String indent) { ... }
}class IntExpr extends Expr {
String getINT() { ... }int value() { ... }void unparse(Stream s, String indent) { ... }
}Compiler Construction 2011 F06-31
Intertype declarations (Static AOP)
Partial class definitions can be written in different modulesA preprocessor can weave together the code to complete (tangled)classes that are compiled by an ordinary compiler.
Compiler Construction 2011 F06-32
Example
class Add extends Expr {Expr expr1, expr2;void print() {expr1.print();System.out.print(’+’);expr2.print();
}}class IntExpr extends Expr {
int value;void print() {System.out.print(value);
}}
Compiler Construction 2011 F06-33
Extract functionality
aspect Print {class Add extends Expr {
Expr expr1, expr2;void Add.print() {
expr1.print();System.out.print(’+’);expr2.print();
}}class IntExpr extends Expr {
int value;void IntExpr.print() {
System.out.print(value);}
}}
Compiler Construction 2011 F06-34
More functionality
aspect Value {class Add extends Expr {
Expr expr1, expr2;int Add.value() {
int n1 = expr1.value();int n2 = expr2.value();return n1+n2:
}}class IntExpr extends Expr {
int value;int IntExpr.value() {
return value;}
}}
Compiler Construction 2011 F06-35
Weave
java -jar jastadd2.jar Expr.ast Print.jadd Value.jadd
produces
class Add extends Expr {Expr expr1, expr2;void print() {expr1.print();System.out.print(’+’);expr2.print();
}int value() {int n1 = expr1.value();int n2 = expr2.value();return n1+n2:
}}
Compiler Construction 2011 F06-36
The JastAdd system
Typed AST
I Generates AST classes with typed access methods from anabstract grammar
Intertype declarations
I partial class definitions for AST classes are written in .jaddfiles.JastAdd weaves in these partial definitions into the generatedAST classes
Rewritable Reference Attribute Grammars
I Declarative computations using attributes and equations
I Declarative transformations of the AST
I Guest lecture by Emma Soderberg.
Compiler Construction 2011 F06-37
Modularizing our example
abstract Expr;BinExpr: Expr ::= Expr Expr;Add: BinExpr;IntExpr: Expr;
aspect Value {abstract int Expr.value();int Add.value() {...}int IntExpr.value() {...}
aspect Print {abstract void Expr.print();void Add.print() {...}void IntExpr.print() {...}
Expr.ast Value.jadd
Print.jadd
jastadd
Expr.javaAdd.java
Compiler Construction 2011 F06-38
JastAdd aspect for the expression evaluator
aspect Value {abstract int Expr.value();int Add.value() {return getLeft().value() + getRight().value();
}
int Sub.value() {return getLeft().value() - getRight().value();
}
int IntExpr.value() {return String.parseInt(getINT());
}}
Compiler Construction 2011 F06-39
What parts of AST classes can be factored out to .jaddfiles?
I Methods
I Instance variables
I “implements” clauses
I “import” clauses
Compiler Construction 2011 F06-40
Example (instance variable)
Add an integer representation of INT values (in addition to theString representation)
aspect IntValue {int Expr.value;...
}
Compiler Construction 2011 F06-41
Visitors
How to modularize in Java (or any other OO language) if we donot have access to AOP mechanisms?
Compiler Construction 2011 F06-42
Example
How can we factor out the code for print()?
class Add extends Expr {Expr expr1, expr2;void print() {expr1.print();System.out.print(’+’);expr2.print();
}}class IntExpr extends Expr {
int value;void print() {System.out.print(value);
}}
Compiler Construction 2011 F06-43
Move functionality
class Add extends Expr { class Visitor {Expr expr1, expr2; void visit(Add node) {void print() { node.expr1.print();expr1.print(); System.out.print(’+’);System.out.print(’+’); node.expr2.print();expr2.print(); }
}}class IntExpr extends Expr { void visit(IntExpr node){
int value; System.out.print(void print() { node.value);System.out.print(value); }
}} }
Compiler Construction 2011 F06-44
Missing functionality
class Add extends Expr { class Visitor {Expr expr1, expr2; void visit(Add node) {
node.expr1.print();System.out.print(’+’);node.expr2.print();
}}
}class IntExpr extends Expr { void visit(IntExpr node){
int value; System.out.print(node.value);
}
} }
Compiler Construction 2011 F06-45
Delegate
class Add extends Expr { class Visitor {Expr expr1, expr2; void visit(Add node) {void accept(Visitor v) { node.expr1.accept(this);v.visit(this); System.out.print(’+’);
node.expr2.accept(this);}
}}class IntExpr extends Expr { void visit(IntExpr node){
int value; System.out.print(void accept(Visitor v) { node.value);v.visit(this); }
}} }
Compiler Construction 2011 F06-46
Why not call visit directly?
class Add extends Expr { class Visitor {Expr expr1, expr2; void visit(Add node) {void accept(Visitor v) { visit(node.expr1);v.visit(this); System.out.print(’+’);
visit(node.expr2);}
}}class IntExpr extends Expr { void visit(IntExpr node){
int value; System.out.print(void accept(Visitor v) { node.value);v.visit(this); }
}} }
Compiler Construction 2011 F06-47
Generalise
class Add extends Expr { interface Visitor {Expr expr1, expr2; void visit(Add node);void accept(Visitor v) { void visit(IntExpr node);v.visit(this); }
class PrintVisitor} implements Visitor {
}class IntExpr extends Expr { void visit(Add node) {
int value; node.expr1.accept(this);void accept(Visitor v) { System.out.print(’+’);v.visit(this); node.expr1.accept(this);
} } ...} }
Compiler Construction 2011 F06-48
Generalise with parameter and return
interface Visitor {Object visit(Add node, Object data);Object visit(IntExpr node, Object data);
}
class IntExpr extends Expr {Expr expr1, expr2;Object accept(Visitor v, Object data) {return v.visit(this, data); }
}}
class PrintVisitor extends Visitor {Object visit(IntExpr node, Object data) {System.out.print(node.value);return null;
}}Compiler Construction 2011 F06-49
Another visitor
class ValueVisitor extends Visitor {Object visit(Add node, Object data) {int n1 = (Integer) node.expr1.accept(this, data);int n2 = (Integer) node.expr2.accept(this, data);return new Integer(n1+n2);
}Object visit(IntExpr node, Object data) {return new Integer(node.value);
}}
Expr expr = new Add(... );expr.accept(new PrintVisitor(), null);int value = expr.accept(new ValueVisitor(), null);
Compiler Construction 2011 F06-50
The Visitor Pattern
Intent
Represent an operation to be performed on the elementsof an object structure.Visitor lets you define a new operation without changingthe classes of the elements on which it operates.
Compiler Construction 2011 F06-51
Sketch
interface Visitor { Object visit(Add, Object); Object visit(Sub, Object);//one visit method for each AST class
class ValueVisitor implements Visitor {Object visit(Add, Object) { ... }Object visit(Sub, Object) { ... }
Visitor.java
ValueVistor.java
UnparseVisitor.java
Expr
class Addaccept(...)
each AST class has anObject accept(Visitor, Object)method
delegates computation
class UnparseVisitor implements Visitor {Object visit(Add, Object) { ... }Object visit(Sub, Object) { ... }
Sub
Compiler Construction 2011 F06-52
Interface Visitor
interface Visitor {Object visit(Add node, Object data);Object visit(Sub node, Object data);Object visit(IntExpr node, Object data);...
}
I The visit method is overloaded for different AST argumenttypes
I Each method returns an untyped object
I Each method has an untyped argument (data)
Compiler Construction 2011 F06-53
Visitor support in AST nodesMethod accept that delegates the computation to a Visitor
abstract class Expr {abstract Object accept(Visitor v, Object data);
}abstract class BinExpr extends Expr {
Object accept(Visitor v, Object data) {return v.visit(this, data);
}}class Add extends BinExpr {
Object accept(Visitor v, Object data) {return v.visit(this, data);
}}class IntExpr extends Expr {
Object accept(Visitor v, Object data) {return v.visit(this, data);
}}
Compiler Construction 2011 F06-54
The evaluator as a visitor
class Evaluator implements Visitor {
}
Compiler Construction 2011 F06-55
To note about this example . . .
I the argument data was not needed for the computation
I the result (of type int) had to be wrapped in an Integer object
I Casts are needed in some places.
I the method value hides implementation detail and makes iteasy to call the visitor from a client
Example of use
Expr e = ...;print("the value is ");println(Evaluator.value(e));
Compiler Construction 2011 F06-56
The unparser as a visitor
class Unparser implements Visitor {
}
Compiler Construction 2011 F06-57
To note about this example . . .
I the argument data is used for representing the argumentindent and needs to be cast to String before use
I the original argument PrintStream s is stored in the Visitorobject and can be used directly by all visit methods
I the result value is not used
I the method unparse hides implementation detail and makes iteasy to call the visitor from a client
Example of use
Program p = ...;PrintStream s = ...;Unparser.unparse(p, s);
Compiler Construction 2011 F06-58
One more example
Count the number of identifiers in a program
abstract Stmt;IfStmt : Stmt ::= Cond:Expr Then:Stmt [Else:Stmt];...abstract Expr;abstract BinExpr : Expr ::= Left:Expr Right:Expr;Add : BinExpr ::= ;Sub : BinExpr ::= ;Int : Expr ::= <INT:String>;IdExpr : Expr ::= <ID:String>;...
How can the Visitor be implemented?
Compiler Construction 2011 F06-59
TraversingVisitor
class TraversingVisitor implements Visitor {Object visit(IfStmt node, Object data) {node.getCond().accept(this, data);node.getThen().accept(this, data);if (node.hasElse()) {
node.getElse().accept(this, data);}
}Object visit(Add node, Object data) {node.getLeft().accept(this, data);node.getRight().accept(this, data);
}}
The code above is independent of the computation and could havebeen generated from the abstract grammar (but this is currentlynot done in JJTree or JastAdd).Compiler Construction 2011 F06-60
CountIdentifiers as a visitor
class CountIdentifiers extends TraversingVisitor {
}
Example of use
Compiler Construction 2011 F06-61
Intertype declarations vs. Visitor
intertype declar-tions
Visitor
what can be mod-ularized?
instance variables,methods, imple-ments clauses
only methods
types for argu-ments and returnvalues
arbitrary Object visit(..., Object)(one untyped argumentand one result)
separate compila-tion?
no – preprocessorrequired
yes
pure Java? no – requires addi-tional tools
yes
Compiler Construction 2011 F06-62
Using the modularization techniques
InterpretationUnparsingMetricsSemantic Analysis
I Name analysis – connect an identifier to its declaration
I Type analysis ? compute the type of an expression
I . . .
Code generation
I Compute the size needed for objects and methods
I Generate instructions
I . . .
Compiler Construction 2011 F06-63