把那些隐隐约约的东西说清楚写下来,还是挺不容易的。
- idea安装插件
安装完毕之后重启idea - 新建maven工程,名字随便起,pom如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>antlr4</groupId>
<artifactId>antlr4</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.7.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.7</version>
<executions>
<execution>
<id>antlr</id>
<goals>
<goal>antlr4</goal>
</goals>
<phase>none</phase>
</execution>
</executions>
<configuration>
<outputDirectory>src/test/java</outputDirectory>
<listener>true</listener>
<treatWarningsAsErrors>true</treatWarningsAsErrors>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 建立.g4文件,写语法
grammar Expr;
prog : stat+;
stat: expr NEWLINE # printExpr
| ID '=' expr NEWLINE # assign
| NEWLINE # blank
;
expr: expr op=('*'|'/') expr # MulDiv
| expr op=('+'|'-') expr # AddSub
| INT # int
| ID # id
| '(' expr ')' # parens
;
MUL : '*' ; // assigns token name to '*' used above in grammar
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
ID : [a-zA-Z]+ ;
INT : [0-9]+ ;
NEWLINE:'\r'? '\n' ;
WS : [ \t]+ -> skip;
- 配置generate,生成文件
在文件上右键,先完成第一步,配置如下,然后完成第二步,生成解析程序的文件。
上图箭头所指,是生成使用访问者模式解析类,后续再解释。 - 实现自己的Visitor,在访问到指定节点时做相应的动作,比如,赋值的时候保存值,取值的时候返回值
public class EvalVisitor extends ExprBaseVisitor<Integer> {
private Map<String,Integer> memory = new HashMap<>();
@Override
public Integer visitPrintExpr(ExprParser.PrintExprContext ctx) {
Integer value = visit(ctx.expr());
System.out.println(value);
return value;
}
@Override
public Integer visitAssign(ExprParser.AssignContext ctx) {
String id = ctx.ID().getText();
Integer value = visit(ctx.expr());
this.memory.put(id, value);
return value;
}
@Override
public Integer visitInt(ExprParser.IntContext ctx) {
return Integer.valueOf(ctx.INT().getText());
}
@Override
public Integer visitMulDiv(ExprParser.MulDivContext ctx) {
Integer left = visit(ctx.expr(0));
Integer right = visit(ctx.expr(1));
if (ctx.op.getType() == ExprParser.MUL){
return left * right;
}else{
return left / right;
}
}
@Override
public Integer visitParens(ExprParser.ParensContext ctx) {
Integer value = visit(ctx.expr());
return value;
}
@Override
public Integer visitAddSub(ExprParser.AddSubContext ctx) {
int left = visit(ctx.expr(0));
int right = visit(ctx.expr(1));
if(ctx.op.getType() == ExprParser.ADD){
return left + right;
}else{
return left - right;
}
}
@Override
public Integer visitId(ExprParser.IdContext ctx) {
return this.memory.get(ctx.ID().getText());
}
}
- 测试
public class ExprTest {
public static void main(String[] args) {
CodePointCharStream inputStream = CharStreams.fromString("a=10\nb=10\n10*(1+b)\n");
ExprLexer lexer = new ExprLexer(inputStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
ExprParser parser = new ExprParser(tokenStream);
ParseTree parseTree = parser.prog();
EvalVisitor visitor = new EvalVisitor();
visitor.visit(parseTree);
}
}
未完待续