1. 下载jar
#基于java8
wget https://www.antlr.org/download/antlr-4.5-complete.jar
2. 下载词法定义、语法定义
git clone https://github.com/antlr/grammars-v4.git
#grammars-v4/java/java8/Java8Parser.g4
#grammars-v4/java/java8/Java8Lexer.g4
3. 生成解析器
java -cp antlr-4.5-complete.jar org.antlr.v4.Tool Java8Parser.g4
java -cp antlr-4.5-complete.jar org.antlr.v4.Tool Java8Lexer.g4
#生成了: Java8Lexer.java Java8Lexer.tokens Java8Parser.java Java8Parser.tokens Java8ParserListener.java Java8ParserBaseListener.java
#或者
alias antlr4='java -Xmx500M -cp "./antlr-4.10.1-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
alias grun='java -Xmx500M -cp "./antlr-4.10.1-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig'
antlr4 Java8Parser.g4
antlr4 Java8Lexer.g4
4. 使用演示
原材料
import java.util.List;
import java.util.Map;
public class Demo {
public static final long serialVersionUID = 1L;
private static final void buszFunc1(int x, String y) {
int[] arr={1,-8,90,-23};
int swap;
for(int i =0; i <arr.length; i++){
return;
for(int k =i; k < arr.length; k++){
arr[i] = swap;
swap=arr[k];
arr[k]=swap;
}
}
return;
}
protected int[ ] utilFunc() {
int userCount=0;
while(false){
userCount++;
userCount--;
}
return null;
}
List<Map<String, Integer>>[] debugFunc() {
return null;
}
}
antlr4操纵原材料
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.TerminalNodeImpl;
import org.antlr.v4.runtime.tree.xpath.XPath;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* from : https://www.freesion.com/article/6326863956/
* */
public class InsertSerialIDTest {
public static void main(String[] args) throws Exception {
//1.读入java源码文件
File file = new File("src/main/resources/Demo.java");
System.out.println(file.exists());
CharStream input=CharStreams.fromPath(file.toPath());
//2.词法分析
Java8Lexer lexer = new Java8Lexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
//3.语法分析
Java8Parser parser = new Java8Parser(tokens);
ParseTree tree = parser.compilationUnit(); // parse
//4.将语法树喂给自定义监听器
ParseTreeWalker walker = new ParseTreeWalker(); // create standard walker
InsertSerialIDListener extractor = new InsertSerialIDListener(tokens);
walker.walk(extractor, tree); // initiate walk of tree with listener
//5.打印修改后的java源码
String javaSourceModified=extractor.rewriter.getText();
System.out.println(javaSourceModified);
//各种尝试:单纯的在token列表中找到第一个void, 这貌似没什么用, 因为拿不到该void的parent
Token voidFirst = tokens.getTokens().stream().filter(ti -> Java8Lexer.VOID == ti.getType()).findFirst().orElseGet(null);
//各种尝试:xpath拿语法树中的所有方法声明
//https://www.antlr.org/api/Java/org/antlr/v4/runtime/tree/xpath/XPath.html
//https://github.com/antlr/antlr4/blob/master/doc/tree-matching.md
XPath xpath = new XPath(parser, "//methodDeclaration");
Collection<ParseTree> methodDeclarationList_ = xpath.evaluate(tree);
/**methodDeclarationList_[0]:{@link Java8Parser.MethodDeclarationContext}*/
Collection<ParseTree> methodDeclarationList = new XPath(parser, "//methodDeclaration").evaluate(tree);
/**methodDeclarationList[0]:{@link Java8Parser.MethodDeclarationContext}*/
Collection<ParseTree> anyNode = new XPath(parser, "/*").evaluate(tree);
/**anyNode[0]:{@link Java8Parser.CompilationUnitContext}*/
Java8Parser.ClassBodyContext classBodyContext= (Java8Parser.ClassBodyContext) find_element_by_xpath(parser,tree,"/compilationUnit/typeDeclaration/classDeclaration/normalClassDeclaration/classBody");
find_elements_by_xpath(parser,classBodyContext,"//classBodyDeclaration");
Collection<ParseTree> methodDeclarationContext = find_elements_by_xpath(parser, classBodyContext, "//classBodyDeclaration/classMemberDeclaration/methodDeclaration");
//各种尝试:试着拿到Demo.java的方法buszFunc1
//https://stackoverflow.com/questions/23092081/antlr4-visitor-pattern-on-simple-arithmetic-example
//https://wizardforcel.gitbooks.io/antlr4-short-course/content/calculator-visitor.html
VisitInt visitor = new VisitInt();
visitor.visit(tree);
}
public static final ParseTree find_element_by_xpath(Java8Parser parser, ParseTree tree, String xpath){
Collection<ParseTree> elements = find_elements_by_xpath(parser, tree, xpath);
if(elements==null||elements.size()==0){
return null;
}
if(elements.size()>1){
String msg=String.format("warning:find_element_by_xpath:elements.size:%s >1",elements.size());
System.out.println(msg);
}
return (ParseTree) elements.toArray()[0];
}
public static final Collection<ParseTree> find_elements_by_xpath(Java8Parser parser, ParseTree tree, String xpath){
Collection<ParseTree> xpathEvalResult = new XPath(parser, xpath).evaluate(tree);
return xpathEvalResult;
}
public static class VisitInt extends Java8ParserBaseVisitor<Integer>{
private static final <ParserRuleContextSubType extends ParserRuleContext> ParserRuleContextSubType findFirst(List<ParseTree> children, final Class<ParserRuleContextSubType> clz){
/**
* 原写法:
Java8Parser.MethodBodyContext methodBody = (Java8Parser.MethodBodyContext) ctx.children.stream().filter(ci -> ci instanceof Java8Parser.MethodBodyContext).findFirst().orElseGet(null);
此写法可读性较高, 但 由于 java instanceof不能搭配泛型 只能把instanceof改成比较Class对象是否为同一个了, 这样改可读性查 但由于java的泛型擦除 导致对java只能如此改了.
*/
return (ParserRuleContextSubType)Optional.ofNullable(children)
.orElse(Collections.emptyList())
.stream()
.filter(ci -> ci.getClass()==clz)
.findFirst()
.orElse(null);
}
@Override
public Integer visitMethodDeclaration(Java8Parser.MethodDeclarationContext ctx) {
/** 1. 参照文法Java8Parser.g4 从 方法声明 中 拿到 方法头、方法体
* 参照 Java8Parser.g4 : 第425行 产生式:
"""
methodDeclaration
: methodModifier* methodHeader methodBody
;
"""
文法的非终结符methodDeclaration 由 入参 ctx 持有,
文法的非终结符methodHeader 由 局部变量 methodBodyContext 持有,
文法的非终结符methodBody 由 局部变量 methodHeaderContext 持有
*/
Java8Parser.MethodHeaderContext methodHeaderContext = findFirst(ctx.children, Java8Parser.MethodHeaderContext.class);
Java8Parser.MethodBodyContext methodBodyContext = findFirst(ctx.children, Java8Parser.MethodBodyContext.class);
//methodBody就是Demo.java中的方法buszFunc1
/** 2. 参照文法Java8Parser.g4 从 方法头 中 拿到 返回类型
* 继续参照Java8Parser.g4中的产生式(第442行):
"""
methodHeader
: result methodDeclarator throws_?
| typeParameters annotation* result methodDeclarator throws_?
;
"""
文法的非终结符methodHeader 由 局部变量 methodBodyContext 持有,
文法的非终结符result 由 局部变量 resultContext 持有,
*/
Java8Parser.ResultContext resultContext = findFirst(methodHeaderContext.children, Java8Parser.ResultContext.class);
TerminalNodeImpl resultTerminalNode = (TerminalNodeImpl) resultContext.children.get(0);
boolean methodResultTypeIsVoid=resultTerminalNode.symbol.getType()==Java8Lexer.VOID;
//methodResultTypeIsVoid:方法返回类型是否为void
return 0;
}
//@Override public T visitMethodHeader(Java8Parser.MethodHeaderContext ctx) { return visitChildren(ctx); }
@Override
public Integer visitMethodHeader(Java8Parser.MethodHeaderContext ctx){
// return visitChildren(ctx);
return 0;
}
}
}