1.maven 依赖
<dependencies>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId>
<version>4.7.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.7.2</version>
<executions>
<execution>
<configuration>
<listener>true</listener>
<visitor>true</visitor>
</configuration>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>package</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/target/generated-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
2.g4文件
创建目录 src/main/antlr4/org/example/parser
创建文件 Calculator.g4
// CalculatorParser.g4
// 语法文件
grammar Calculator;
// 引入词法文件,会根据 CalculatorLex.g4 生成 java 类,而是根据 Calculator.g4 生成文件
// import CalculatorLex;
// 指定词法规则文件,会根据 CalculatorLex.g4 生成 java 类
//options {
// tokenVocab = CalculatorLex;
//}
start:
expr EOF
;
expr: expr op=('*'|'/') expr # MulDiv
| expr op=('+'|'-') expr # AddSub
| INT # int
| '(' expr ')' # parens
;
INT : [0-9]+ ;
MUL : '*' ;
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
执行 mvn package
编译,会在 target/generated-sources/antlr4
目录下,看到编译出的 java 文件
3.java 文件
CalculatorVisitorImpl.java
package org.example;
import org.example.parser.CalculatorBaseVisitor;
import org.example.parser.CalculatorParser;
public class CalculatorVisitorImpl extends CalculatorBaseVisitor<Integer> {
@Override
public Integer visitStart(CalculatorParser.StartContext ctx) {
if (ctx.expr() != null) {
return visit(ctx.expr());
}
return null;
}
@Override
public Integer visitMulDiv(CalculatorParser.MulDivContext ctx) {
int left = visit(ctx.expr(0));
int right = visit(ctx.expr(1));
if (ctx.op.getType() == CalculatorParser.MUL) {
return left * right;
}
return left / right;
}
@Override
public Integer visitAddSub(CalculatorParser.AddSubContext ctx) {
int left = visit(ctx.expr(0));
int right = visit(ctx.expr(1));
if (ctx.op.getType() == CalculatorParser.ADD) {
return left + right;
}
return left - right;
}
@Override
public Integer visitInt(CalculatorParser.IntContext ctx) {
return Integer.valueOf(ctx.INT().getText());
}
@Override
public Integer visitParens(CalculatorParser.ParensContext ctx) {
return visit(ctx.expr());
}
}
CalculatorListenerImpl.java
package org.example;
import org.example.parser.CalculatorBaseListener;
import org.example.parser.CalculatorParser;
import java.util.Deque;
import java.util.LinkedList;
public class CalculatorListenerImpl extends CalculatorBaseListener {
private final Deque<Integer> stack = new LinkedList<>();
public Integer getResult() {
return this.stack.peek();
}
@Override
public void exitMulDiv(CalculatorParser.MulDivContext ctx) {
int right = this.stack.pop();
int left = this.stack.pop();
if (ctx.op.getType() == CalculatorParser.MUL) {
this.stack.push(left * right);
} else {
this.stack.push(left / right);
}
}
@Override
public void exitAddSub(CalculatorParser.AddSubContext ctx) {
int right = this.stack.pop();
int left = this.stack.pop();
if (ctx.op.getType() == CalculatorParser.ADD) {
this.stack.push(left + right);
} else {
this.stack.push(left - right);
}
}
@Override
public void exitInt(CalculatorParser.IntContext ctx) {
Integer number = Integer.parseInt(ctx.INT().getText());
this.stack.push(number);
}
}
4.测试
@Test
public void testVisitor() {
// 将输入字符串化为输入流(也可以是 ANTLRInputStream )然后传入词法分析器
CalculatorLexer lexer = new CalculatorLexer(CharStreams.fromString("(1+2)-(3+4)"));
// 转换成 Token 流传入语法分析器
CalculatorParser parser = new CalculatorParser(new CommonTokenStream(lexer));
// 因为词法文件里最外层定义了 start 规则,这里就能从 parser.start() 解析并获取规则树
CalculatorParser.StartContext context = parser.start();
ParseTree parseTree = context;
// 计算
CalculatorVisitorImpl visitor = new CalculatorVisitorImpl();
Integer result = visitor.visit(parseTree);
// Integer result = parseTree.accept(visitor);
System.out.println(result);
}
@Test
public void testListener() {
// 将输入字符串化为输入流(也可以是 ANTLRInputStream )然后传入词法分析器
CalculatorLexer lexer = new CalculatorLexer(CharStreams.fromString("(1+2)-(3+4)"));
// 转换成 Token 流传入语法分析器
CalculatorParser parser = new CalculatorParser(new CommonTokenStream(lexer));
// 因为词法文件里最外层定义了 start 规则,这里就能从 parser.start() 解析并获取规则树
CalculatorParser.StartContext context = parser.start();
ParseTree parseTree = context;
// 计算
CalculatorListenerImpl listener = new CalculatorListenerImpl();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(listener, parseTree);
Integer result = listener.getResult();
System.out.println(result);
}