ANTLR 是用JAVA写的语言识别工具,它用来声明语言的语法,简称为“元语言”。
Idea中配置使用
pom.xml添加
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.7</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
Idea setting中安装ANTLR插件(我本机安装完了)? ?Eclipse也类似的安装插件
?示例:计算机四则计算(官网照抄)
1、新建g4文件,如Math.g4
grammar Math;
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;
?Idea 安装完ANTLR插件 右键g4文件可以看到,点击Configure ANTLR...
配置目录如下,按照你们自己的目录设置,点击OK
?右键Math.g4文件,点击Generate ANTLR Recognizer
自动生成代码:
编写实现类,继承上面自动生成的类MathBaseVisitor,实现计算
public class MathVisitorImp extends MathBaseVisitor<Integer> {
// 存储变量的值
private Map<String, Integer> variable;
public MathVisitorImp() {
variable = new HashMap<>();
}
// 当遇到printExpr节点,计算出exrp的值,然后打印出来
@Override
public Integer visitPrintExpr(MathParser.PrintExprContext ctx) {
Integer result = ctx.expr().accept(this);
System.out.println(result);
return null;
}
// 分别获取子节点expr的值,然后做加减运算
@Override
public Integer visitAddSub(MathParser.AddSubContext ctx) {
Integer param1 = ctx.expr(0).accept(this);
Integer param2 = ctx.expr(1).accept(this);
if (ctx.op.getType() == MathParser.ADD) {
return param1 + param2;
}else {
return param1 - param2;
}
}
// 分别获取子节点expr的值,然后做乘除运算
@Override
public Integer visitMulDiv(MathParser.MulDivContext ctx) {
Integer param1 = ctx.expr(0).accept(this);
Integer param2 = ctx.expr(1).accept(this);
if (ctx.op.getType() == MathParser.MUL) {
return param1 * param2;
}else {
return param1 / param2;
}
}
// 当遇到int节点,直接返回数据
@Override
public Integer visitInt(MathParser.IntContext ctx) {
return Integer.parseInt(ctx.getText());
}
// 当遇到Id节点,从变量表获取值
@Override
public Integer visitId(MathParser.IdContext ctx) {
return variable.get(ctx.getText());
}
// 当遇到赋值语句,获取右边expr的值,然后将变量的值保存到variable集合
@Override
public Integer visitAssign(MathParser.AssignContext ctx) {
String name = ctx.ID().getText();
Integer value = ctx.expr().accept(this);
variable.put(name, value);
return null;
}
}
测试:
public class MathVisitorTest {
public static void exec(String input) {
MathLexer lexer = new MathLexer(CharStreams.fromString(input));
CommonTokenStream tokens = new CommonTokenStream(lexer);
MathParser parser = new MathParser(tokens);
parser.setBuildParseTree(true);
ParseTree root = parser.prog();
MathBaseVisitor<Integer> visitor = new MathVisitorImp();
root.accept(visitor);
}
public static void main(String[] args) {
String input = "1+2+3+5-7+1\n";
// String input = "a = 14\n" +
// "b = a - 3\n" +
// "a + b\n";
exec(input);
}
}
结果输出为:5
g4检查语法是否通过
1.新建g4Test.txt内容如下
a=3
b=4
c=a+b
d=a+b+c
e=4**2
f=d+e
2.测试g4是否通过
public class g4Main {
public static void main(String[] args) throws Exception {
CharStream inputStream = CharStreams.fromFileName("D:\\g4\\g4Test.txt", Charset.forName("UTF-8"));
MathLexer lexer = new MathLexer(inputStream);
CommonTokenStream token=new CommonTokenStream(lexer);
MathParser parser=new MathParser(token);
MathParser.ProgContext tree = parser.prog();
tree.accept(new MathBaseVisitor<Object>(){
@Override
public Object visitPrintExpr(MathParser.PrintExprContext ctx) {
return super.visitPrintExpr(ctx);
}
});
System.out.println("g4执行结束");
}
}
结果输出为:
line 5:4 extraneous input '*' expecting {'(', ID, INT}
g4执行结束
line 5:4? 这是第5行第4列有语法不匹配的情况。
正常去修改Math.g4文件。以匹配语法。
后续会继续补充...
|