第四章-语法分析之认识树节点

 

上一章我们得到了Token序列,而语法分析就是根据Token序列构造抽象语法树的过程,抽象语法树是一种用来描述程序代码语法 结构的树形表示方式,这种结构化的表示方式将为后面语义分析、代码生成阶段提供极大的便利。语法树的每一个节点都代表了程序代码中的一个语法结构,如包、类型、修饰符、运算符、接口、返回值甚至代码注释等都可以是一个语法结构。Javac中,每个语法树节点都对应着一个具体的实现类,这一章将重点介绍抽象语法树上的各个语法树节点,只有认清了抽象语法树上的构造节点才能根据根据一定规则将token序列转换为抽象语法树。

 

由于语法树中涉及到的节点众多,我们可以大概将这些节点归纳为如下3类:

(1)定义及声明 例如编译单元的定义、方法的定义、import导入包的声明等

(2)语句 例如一些流程控制的if语句、while语句、do-while语句及for语句等

(3)表达式 如两个数值相加x+y等

 

1、定义及声明

Javac中有几个定义及声明,下面给出了涉及到的主要的几个语法树节点的继承关系图。

 

 

 

可以看到Javac语法树上的每个节点实现类都继承了一个抽象实现类JCTree,同时也实现了与自己想对应的接口,如JCxxx实现类实现xxxTree接口,而xxxTree接口与JCTree又同时实现了

Tree接口,可以说这个接口是一个顶层接口,代表了任意一个语法树节点。类似的,语句及表达式的实现类也遵循了这样的继承原则,只是语句是通过JCStatement间接继承了JCTree,而表达式是通过JCExpression抽象类间接继承了JCTree。

(1)JCCompilationUnit编译单元

JCCompilationUnit表示一个编译单元,一般是一个源文件内容对应一个编译单元,同时这也是顶层的树节点。所以如果一个文件中定义了多个类,则这些类也属于同一个编译单元。

认识这些树节点的实现类时,关系要认清里面的一些重要的属性,下面看一下JCCompilationUnit节点所包含的其它语法节点,如下:

public List<JCAnnotation> packageAnnotations;
public JCExpression pkgid;
public List<JCTree> defs;

多个包注解将会存储到packageAnnotations集合中,包名存储到pkgid属性,而关于多个类定义则存储到defs集合中。举个例子,首先定义一个包的注解,如下:

package com.test14;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

/**
 * 定义标注在package上的注解
 */
@Target(ElementType.PACKAGE)
public @interface PkgAnnotation {

}

再创建一个package-info类,内容如下:

@PkgAnnotation
package com.test14;
import java.util.HashMap;
class A{} class B{ 

最终package-info类的语法树节点如下:  

 

(2)ImportTree导入声明

用来表示一个具体的import声明,其实现类中定义了两个属性:

public boolean staticImport;
public JCTree qualid;

staticImport表示是否为静态导入,当静态导入时值为true。qualid表示具体导入的内容。例如声明一个HashMap的导入:

import java.util.HashMap;

语法节点qualid为如下JCFieldAccess类型,表示java.util.HashMap,由于是非静态导入,则属性staticImport为false。 

(3)JCModifiers 

用来表示修饰符,如public、abstract、native等,这个语法树节点同时也能表示注解到变量与方法上的注解,JCModifiers.java类中定义的重要属性如下:  

public long flags;
public List<JCAnnotation> annotations;

 

其中flags是一个长整型,在Java中long类型由8个字节表示,最多有64个位,所以可以通过各个位来表示某些有修饰符的树结构,例如类、方法和变量等。具体哪个位代表哪个修饰符是由Flags类来定义的。Flags类中定义了非常多的静态变量,这里只了解一些常量的修饰符就可以了,如下: 

public static final int PUBLIC       = 1<<0; // 0x0001
public static final int PRIVATE      = 1<<1; // 0x0002
public static final int PROTECTED    = 1<<2; // 0x0004
public static final int STATIC       = 1<<3; // 0x0008
public static final int FINAL        = 1<<4; // 0x0010

public static final int SYNCHRONIZED = 1<<5;  // 0x0020
public static final int VOLATILE     = 1<<6;  // 0x0040
public static final int TRANSIENT    = 1<<7;  // 0x0080

public static final int NATIVE       = 1<<8;  // 0x0100
public static final int INTERFACE    = 1<<9;  // 0x0200
public static final int ABSTRACT     = 1<<10; // 0x0400
public static final int STRICTFP     = 1<<11; // 0x0800

也就是long类型64位中的低12位可以表示这些,这样就可以通过一个数来表示所有可能的修饰符组合了,Flags类中也定义了最常量的组合: 

/** Modifier mas
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值