使用openjdk的语法解析器(Parser)解析java源代码

    jsr269提供annotation processor,允许我们在编译器编译过程中挂钩子。http://projectlombok.org/ 的许多功能正是基于此实现。

    但有时候可能需要解析语法正确,但没有语义的Java文件(比如对工程中的单个java源文件的方法等元素建索引),这个时候jsr269就不能满足需求了。此时,我们只要语法树(ast)就可以了,也就是说不需要编译通过,只需要语法解析,可选的parser我找到了3个:

 

-- antlr parser

-- eclipse jdt parser

-- javac parser

 

下面一个例子使用javac parser来获得ast,并采用visitor模式遍历整颗语法树,提取文件中的所有方法。

注意:

     需要在classpath中引入jdk的tools.jar

     很多类不属于标准api,目前只在openjdk6,7上做过测试

 

package org.jilen;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import com.sun.source.tree.MethodTree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.parser.ParserFactory;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.Context;

public class JDKParser {
	private ParserFactory factory;

	public JDKParser() {
		factory = getParserFactory();
	}

	public List<String> parseMethodDefs(String file) throws IOException {
		JCCompilationUnit unit = parse(file);
		MethodScanner scanner = new MethodScanner();
		return scanner.visitCompilationUnit(unit, new ArrayList<String>());

	}

	JCCompilationUnit parse(String file) throws IOException {
		Parser parser = factory.newParser(readFile(file), true, false, true);
		return parser.parseCompilationUnit();
	}

	private ParserFactory getParserFactory() {
		Context context = new Context();
		JavacFileManager.preRegister(context);
		ParserFactory factory = ParserFactory.instance(context);
		return factory;
	}

	CharSequence readFile(String file) throws IOException {
		FileInputStream fin = new FileInputStream(file);
		FileChannel ch = fin.getChannel();
		ByteBuffer buffer = ch.map(MapMode.READ_ONLY, 0, ch.size());
		return Charset.defaultCharset().decode(buffer);
	}
	
	//扫描方法时,把方法名加入到一个list中
	static class MethodScanner extends
			TreeScanner<List<String>, List<String>> {
		@Override
		public List<String> visitMethod(MethodTree node, List<String> p) {
			p.add(node.getName().toString());
			return p;
		}
	}

	public static void main(String[] args) throws IOException {
		JDKParser parser = new JDKParser();
		for (String method : parser.parseMethodDefs("User.java")) {
			System.out.println(method);
		}
	}
}

 

1.parser.parseCompilationUnit();获得语法树

2.MethodScanner扫描整颗语法树,整个扫面其实是fold/reduce过程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值