MastarCpler开发日志(三)——构建AST(抽象语法树)

        在正文之前,突然想发一点小感慨。因为懂得不多,又想自己探索,所以走了很多很多弯路。以前总听别人说,不要怕走弯路,全当鸡汤听了。现在发现,确实如此。

参考:

主要是青木峰郎的《自制编译器》

还有很多网上的资料。

预备知识

        虽然不见得光知道这些就够了,而且虽然我也许了解的也不够准确,但我觉得起码要大概知道。

1、AST和parse树的区别。

        总的来说,AST树比parse树更简洁,只保留了必要的节点。我觉得既然只是做个工程,我也没有追究得那么准确,所以就想画个图意会一下。不过不知道是不是我姿势不对,网上找到的图只是表达式的图,并没有什么函数定义啊类定义啊还有for循环while循环等等的图,所以没办法,我只能按照我的想法设计了。

        怎么说,图画的丑,就是举几个例子分享一下我是怎么搞的吧,主要是以后想怎么用,现在就怎么设计,并不保证这就是AST的模式,而且欢迎批评指正。

2、Java面向对象编程

        对于我一个不太会Java的人来说,Java有些东西还是挺迷的。我当时找了网上教程,还去图书馆找了找书。

这里随便贴一个找到的教程,各位也可以自行寻找:

www.weixueyuan.net/java/rumen_1/

        我觉得现在用到的知识大概如下:

(1)基本语法,当然这和C++很像了,没费什么力。

(2)package之类的组织结构。一个文件里只能有一个public类,类名与文件名相同。

(3)类,那些访问修饰符一定要搞懂,我一开始看到类前面还有public不public之分,就觉得很迷。如教程中所说:

修饰符 说明
public 共有的,对所有类可见。
protected 受保护的,对同一包内的类和所有子类可见。
private 私有的,在同一类内可见。
默认的 在同一包内可见。默认不使用任何修饰符。

(4)继承与多态。这个一定要搞的特别清楚才行。

(5)接口。这个虽然自己没写,但是因为要理解Visitor机制,要看它的源代码,所以接口要知道。

3、Listener和Visitor机制。

        为了遍历parse tree,建立自己的AST,所以要搞清楚Listener和Visitor机制。这里我基本上还是看的上一篇博文推荐的博客:

https://abcdabcd987.com/notes-on-antlr4/

        我自己为应该用Visitor写还是Listener写纠结了好久,最后发现网上看到的几个都用Visitor写的。我觉得Visitor好像更灵活一些,于是也用Visitor写了。

        要用Visitor建立AST,就要自己写一个类BuildAstVisitor继承原有的类<GRAMMAR_NAME>BaseVisitor <Node>。Node是AST的结点类,为了表示不同的结点,它有很多很多子类。

public class Node {
	String id;
	TypeRef type;
	Location loc;
	List<Node> sons;
	Node() {
		sons = new ArrayList<Node>();
		type = TypeRef.buildTypeRef("void"); 
                loc = new location();
        }
	void print(String indentation) {}
}

        其中,id用来记录类似于函数名、类名、运算符、变量名或者常量值,type现在只是记录一些常量或表达式类型,我觉得应该可以以后检查表达式类型,Location是表示位置的类。

        这里还有一点点参考,可以用来感受一下怎么用Visitor建立ASThttp://stackoverflow.org.cn/front/ask/view?ask_id=81496

        我当时为了用嵌入文法写AST,特意学了好半天,结果发现ANTLR  4好像不像ANTLR 3那样支持那种特别简单的建立AST的方法了,所以用的Visitor,并没有用上嵌入文法。有兴趣的可以看一看这个博客还挺全面的:

        https://www.cnblogs.com/6DAN_HUST/archive/2009/01/06/1370359.html

        如果你要问我为什么不直接找《The Definitive ANTLR 4 Reference》来看,我能说我在网上没找着么,又不太想买,好不容易找着一本还是ANTLR 3的,看到里面那种建立AST的方法,大呼精妙然后看了半天,结果发现ANTLR 4不支持了。

        写完以后如果想看一下构建出来的AST是不是你需要的,就需要写一个tester,dfs一下并打印出一些信息。

public class TempTestAst {
	private String delta = "    ";
	void dfs(Node u, String indentation) {
		u.print(indentation + delta);
		for (int i = 0; i < u.sons.size(); ++i)
			dfs(u.sons.get(i), indentation + delta);
	}
}

        比如这样的程序:

int main() {
	while (true) {
	    printf("HelloWorld!");
	}
	return 0;
}

        打印出来就是这个样子:

    <CodeNode> id: null type: void
        <FuncDefNode> id: main type: int
            <CompStatNode> id: null type: void
                <WhileStatNode> id: null type: void
                    <LiteralNode> id: true type: bool
                    <CompStatNode> id: null type: void
                        <ExprStatNode> id: null type: void
                            <FuncExprNode> id: printf type: void
                                <LiteralNode> id: "HelloWorld!" type: string
                <RetStatNode> id: null type: void
                    <LiteralNode> id: 0 type: int

猜你喜欢

转载自blog.csdn.net/u011431896/article/details/79921057