项目的完整代码在 C2j-Compiler
前言
在上一篇完成了符号表的构建,下一步就是输出抽象语法树(Abstract Syntax Tree,AST)
抽象语法树(abstract syntax tree 或者缩写为 AST),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。树上的每个节点都表示源代码中的一种结构。
AST对于编译器是至关重要的,现在的编译型语言一般通过AST来生成IR,解释型语言也可以不用虚拟机而直接遍历AST来解释执行,之后要写解释器和编译器都依赖这个AST
这一篇主要文件有:
- AstBuilder.java
- AstNode.java
- AstNodeImpl.java
- NodeKey.java
- NodeFactory.java
主要数据结构
AST节点的表示
public interface AstNode {
AstNode addChild(AstNode node);
AstNode getParent();
ArrayList<AstNode> getChildren();
void setAttribute(NodeKey key, Object value);
Object getAttribute(NodeKey key);
boolean isChildrenReverse();
void reverseChildren();
AstNode copy();
}
这是对AstNode接口的实现,并且继承HashMap,这里的NodeKey是
TokenType, VALUE, SYMBOL, PRODUCTION, TEXT
对应的value,
- TokenType就是非终结符的类型
- Text用来存储解析对象的文本信息
- Symbol对应的就是变量的符号对象
- Value是对应对象解析的值,比如int a = 1,那么value的值就为1
public class AstNodeImpl extends HashMap<NodeKey, Object> implements AstNode {
private Token type;
private AstNodeImpl parent;
private ArrayList<AstNode> children;
String name;
private boolean isChildrenReverse = false;
public AstNodeImpl(Token type) {
this.type = type;
this.parent = null;
this.children = new ArrayList<>();
setAttribute(NodeKey.TokenType, type);
}
@Override
public AstNode addChild(AstNode node) {
if (node != null) {
children.add(node);
((AstNodeImpl) node).parent = this;
}
return node;
}
@Override
public AstNode getParent() {
return parent;
}
@Override
public void reverseChildren() {
if (isChildrenReverse) {
return;
}
Collections.reverse(children);
isChildrenReverse = true;
}
@Override
public boolean isChildrenReverse() {
return isChildrenReverse;
}
@Override
public ArrayList<AstNode> getChildren() {
reverseChildren();
return children;
}
@Override
public void setAttribute(NodeKey key, Object value) {
if (key == NodeKey.TEXT) {
name = (String) value;
}
put(key, value);
}
@Override
public Object getAttribute(NodeKey key) {
return get(key);
}
@Override
public String toString() {
String info = "";
if (get(NodeKey.VALUE) != null) {
info += "Node Value is " + get(NodeKey.VALUE).toString();
}
if (get(NodeKey.TEXT) != null) {
info += "\nNode Text is " + get(NodeKey.TEXT).toString();
}
if (get(NodeKey.SYMBOL) != null) {
inf