Javac工作原理分析(2):语法分析器

本文详细介绍了javac编译器的工作原理,特别是语法分析阶段,如何将词法分析后的Token流构建成语法树。讲解了语法树的结构,包括每个节点的类型、接口实现以及重要属性。此外,还通过示例展示了import语句和类声明的解析过程,强调了TreeMaker在生成语法节点中的作用。
摘要由CSDN通过智能技术生成

语法分析器是将词法分析器分析的Token流组建成更加结构化的语法树,也就是将一个个单词组装成一句话,一个完整的语句。哪些词组合在一起是主语、哪些是谓语、宾语、定语…要做进一步区分。
语法树及各种语法节点对应的类关系图如下:


这里写图片描述

每个语法树上的节点都是com.sun.tools.javac.tree.JCTree的一个实例,关于语法树有如下规则:
1).每个语法节点都会实现一个接口xxxTree,这个接口又继承自com.sun.source.tree.Tree接口,如IfTree语法节点表示一个if类型的表达式,BinaryTree语法节点代表一个二元操作表达式等
2).每个语法节点都是JCTree的子类,并且会实现第一节点中的xxxTree接口类,这个类的名称类似于JCxxx,如实现IfTree接口的实现类为JCIf,实现BinaryTree接口的类为JCBinary等
3).所有的JCxxx类都作为一个静态内部类定义在JCTree中
JCTree中有3个重要属性需要说明说明一下:
TreeTag:每个语法节点都会用一个整形常数表示,并且每个节点类型的数值是在前一个的基础上加1。顶层节点TOPLEVEL是1,而IMPORT节点等于TOPLEVEL加1,等于2
pos:也是一个整数,它存储的是这个语法节点在源代码中的起始位置,一个文件的位置是0,而-1表示不存在
type:表示这个节点是什么java类型,如int、float还是String

回顾一下package的词法分析方法

public JCExpression qualident(boolean allowAnnos) {
        JCExpression t = toP(F.at(token.pos).Ident(ident()));
        while (token.kind == DOT) {
            int pos = token.pos;
            nextToken();
            List<JCAnnotation> tyannos = null;
            if (allowAnnos) {
                tyannos = typeAnnotationsOpt();
            }
            t = toP(F.at(pos).Select(t, ident()));
            if (tyannos != null && tyannos.nonEmpty()) {
                t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
            }
        }
        return t;
    }

该函数中第一句就是调用TreeMaker类,根据Name对象构建了一个JCIdent语法节点。

JCExpression t = toP(F.at(token.pos).Ident(ident()));

根据上一篇文章所说,Package节点解析完成后会进入while循环,首先解析importDeclaration,解析规则与pakcage的类似:首先检查Token是不是IMPORT,如果是,用import的语法规则来解析import节点,最后构造一个import语法树。源码如下:

protected JCTree importDeclaration() {
    int pos = token.pos;
    nextToken();
    boolean importStatic = false;
    if (token.kind == STATIC) {
        importStatic = true;
        nextToken();
    }
    JCExpression pid = toP(F.at(token.pos).Ident(ident()));
    do {
        int pos1 = token.pos;
        accept(DOT);
        if (token.kind == STAR) {
            pid = to(F.at(pos1).Select(pid, names.asterisk));
            nextToken();
            break;
        } else {
            pid = toP(F.at(pos1).Select(pid, ident()));
        }
    } while (token.kind == DOT);
    accept(SEMI);
    return toP(F.at(pos
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值