Abstract syntax
Abstract grammars are specified in .ast files and correspond to a Java class hierarchy.
Predefined Java classes in the hierarchy:
Abstract syntax constructs in the .ast file
|
|
|
|
|
|
abstract A; |
abstract class A extends ASTNode { } |
|
B: A ::= ...; |
B is a concrete subclass of A |
class B extends A { } |
C: A ::= A B C; |
C has three children of types A, B,
and C. |
class C extends A { A getA(); B getB(); C getC(); |
D: A; |
D has no children. |
class D extends A { } |
E: A ::= A [B] C* <D>; |
E has a child of type A, an optional
child of type B, |
class E extends A { A getA(); boolean hasB(); B getB(); int getNumC(); C getC(int); String getD(); setD(String); } |
|
|
|
F: A ::= Foo:A Bar:B; |
It is possible to name children. |
class F extends A { A getFoo(); B getBar(); } |
G: A ::= A First:B C Second:B D; |
Note! If there is more than one child of the same
type, they must |
class G extends A { A getA(); B getFirst(); C getC(); B getSecond(); D getD(); } |
Tokens are implictly typed by String. But you can also
give a token |
|
|
A ::= <T> |
Here, T is a token of the Java type String. |
class A extends ASTNode { String getT(); setT(String); } |
A ::= <T:String> |
This is equivalent to the example above. |
|
A ::= <T:int> |
Here, T is a token of the Java primitive type int. |
class A extends ASTNode { int getT(); setT(int); } |
The class hierarchy can contain any number of levels. |
|
|
For example: |
abstract A; abstract B: A; C: B; D: C; |
abstract class A extends ASTNode { } abstract class B extends A { } class C extends B { } class D extends C { } |
|
|
|
abstract A ::= B C; D: A; E: A; |
Children are inherited by subclasses |
abstract class A extends ASTNode { B getB(); C getC(); } class D extends A { } class E extends A { } |
abstract A ::= B C; D: A ::= F; |
Subclasses can add children to those specified by the superclass. |
abstract class A extends ASTNode { B getB(); C getC(); } class D extends A { F getF(); } |
... example to be added ... |
Subclasses can repeat/override children ... (to be explained) |
|
|
|
|
A ::= B C /D/ |
A has three children: a B child, a C child, and a D
child. The D child |
abstract class A { B getB(); C getC(); D getD(); } |
About the implementation of Optionals and Lists
The AST representation has additional Opt and List nodes in order to implement children that are optionals or lists. The normal typed traversal API bypasses these implementation nodes, so you will not see them. But you can access the Opt and List nodes by additional implementation level traversal methods like getBOpt() and getDList() below. Note also that if you use the untyped traversal methods (getChild(), etc.), you will stop also on the Opt and List nodes. Examples:
.ast construct |
Implementation structure |
Java API for implementation level traversal |
A ::= [B] |
class A extends ASTNode { private Opt theBOpt; // Never null } class Opt extends ASTNode { private ASTNode theNode; // Null if child is not present } |
class A extends ASTNode { ... Opt getBOpt(); } |
C ::= D* |
class C extends ASTNode { private List theDList; // Never null } class List extends ASTNode { private ...; // Representation of the list; } |
class C extends ASTNode { ... List getDList(); } |
Creating AST nodes
Use the following constructor API to create the AST. Typically you create the AST in the action routines of your parser. But you can of course also create an AST by coding it explicitly, e.g., in a test case. If you use JavaCC+JJTree, see below.
AST class |
Java API for creating AST nodes |
A ::= B C [D] E* <G> |
class A extends ASTNode { A(B, C, Opt, List, String); //Arguments must not be null } |
ASTList |
class ASTList extends ASTNode { ASTList() ASTList.add(ASTNode); // Returns the same ASTList object } |
ASTOpt |
class ASTOpt extends ASTNode { ASTOpt() ASTOpt(ASTNode); // The argument may be null } |
Building ASTs using JJTree
If you use JJTree, the creational code is generated. You use the "#X" notation in the JJTree specification to guide the node creation.JJTree maintains a stack of created nodes. The "#X" notation means:
- create a new object of type X
- pop the nodes that were created during this parse method and insert them as children to the new X node
- then push the new X node
You need to explicitly create List and Opt nodes. When the parsing structure does not fit the abstract tree, e.g. when parsing expressions, you need to use some additional tricks. You also need to set token values explicitly. An example is available in lab 3-4 in the Lund University compiler course. Look at the CalcTree example and the file calc.jjt.