文章目录
前言
提示:网上讲述ANTLR入门的教程太多了,本文是在Windows X86 64位机器下配置运行的,仅供参考使用。这里感谢@一棵树和一枝猪的博客!
提示:以下是本篇文章正文内容,下面案例可供参考
一、antlr是什么?
antlr是一个非常强大的语法分析生成工具,可用于读取、处理、执行和翻译结构化的文本或二进制文件。它被广泛应用于学术领域和工业生产领域,是众多语言、工具和框架的基石。
二、使用步骤
声明:这里假设已经在电脑上配置好Java和ANTLR环境了。
具体配置可参考这个链接
1.引入库
自建一个Calc.g4文件代码如下:
grammar Calc;
prog : stat+;
stat : expr # printExpr
| ID '=' expr # assign
| 'print(' ID ')' # print
;
expr : <assoc=right> expr '^' expr # power
| expr op=(MUL|DIV) expr # MulDiv
| expr op=(ADD|SUB) expr # AddSub
| sign=(ADD|SUB)?NUMBER # number
| ID # id
| '(' expr ')' # parens
;
ID : [a-zA-Z]+;
NUMBER : [0-9]+('.'([0-9]+)?)?
| [0-9]+;
COMMENT : '/*' .*? '*/' -> skip;
LINE_COMMENT : '//' .*? '\r'? '\n' -> skip;
WS : [ \t\r\n]+ -> skip;
MUL : '*';
DIV : '/';
ADD : '+';
SUB : '-';
2.写一个EvalVisitor.java类
代码如下(示例):
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
public class EvalVisitor extends CalcBaseVisitor<Double> {
Map<String, Double> memory = new HashMap<String, Double>();
//id = expr
@Override
public Double visitAssign(CalcParser.AssignContext ctx){
String id = ctx.ID().getText();
Double value = visit(ctx.expr());
memory.put(id, value);
return value;
}
// expr
@Override
public Double visitPrintExpr(CalcParser.PrintExprContext ctx) {
Double value = visit(ctx.expr());
//保留两位有数字的方法
DecimalFormat df = new DecimalFormat("#.##");
String s_value = df.format(value);
System.out.println(s_value);
return 0.0;
}
//print
@Override
public Double visitPrint(CalcParser.PrintContext ctx){
String id = ctx.ID().getText();
Double value=0.0;
if(memory.containsKey(id)) value = memory.get(id);
DecimalFormat df = new DecimalFormat("#.##");
String s_value = df.format(value);
System.out.println(s_value);
return value;
}
//Number
@Override
public Double visitNumber(CalcParser.NumberContext ctx){
int size = ctx.getChildCount();
if(size == 2){
if(ctx.sign.getType() == CalcParser.SUB){
return -1 * Double.valueOf(ctx.getChild(1).getText());
}else{
return Double.valueOf(ctx.getChild(1).getText());
}
}else{
return Double.valueOf(ctx.getChild(0).getText());
}
}
//ID
@Override
public Double visitId(CalcParser.IdContext ctx){
String id = ctx.ID().getText();
if(memory.containsKey(id)) return memory.get(id);
return 0.0;
}
//expr op=('*'|'/') expr
@Override
public Double visitMulDiv(CalcParser.MulDivContext ctx) {
Double left = visit(ctx.expr(0));
Double right = visit(ctx.expr(1));
if(ctx.op.getType() == CalcParser.MUL){
return left * right;
}else{
if(right == 0 || right == 0.0){
System.out.println("Divisor can not be zero");
return 0.0;
}else{
return left / right;
}
}
}
//expr op=('+'|'-') expr
@Override
public Double visitAddSub(CalcParser.AddSubContext ctx){
Double left = visit(ctx.expr(0));
Double right = visit(ctx.expr(1));
if(ctx.op.getType() == CalcParser.ADD)
return left + right;
return left - right;
}
// '(' expr ')'
@Override
public Double visitParens(CalcParser.ParensContext ctx){
return visit(ctx.expr());
}
// '^'
@Override
public Double visitPower(CalcParser.PowerContext ctx){
Double base = visit(ctx.expr(0));
Double exponet = visit(ctx.expr(1));
return Math.pow(base, exponet);
}
}
3.写一个Calc.java类(主类)
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.InputStream;
public class Calc {
public static void main(String[] args) throws Exception {
CharStream input;
if(args.length == 1) {
String fileName = String.valueOf(args[0]);
input = CharStreams.fromFileName(fileName);
}else if(args.length > 1 || args.length < 0){
throw new Exception("the number of arguments is false, Please only give the source file or nothing and then you input your text");
}else {
InputStream is = System.in;
input = CharStreams.fromStream(is);
}
CalcLexer lexer = new CalcLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
CalcParser parser = new CalcParser(tokens);
ParseTree tree = parser.prog();
EvalVisitor eval = new EvalVisitor();
eval.visit(tree);
System.out.println(tree.toStringTree(parser));
}
}
4.写一个自定义的calc.txt文件
3+6*8-9/(7-4)
2*3-6+4
9/3+(6/2)
5*4+((6*7)-(3*2))/4
4.执行命令
antlr4 -no-listener -visitor Calc.g4
javac *.java
java Calc 或 java Calc calc.txt
grun Calc prog -gui calc.txt #可看生成树
5.运行结果
- 执行
java Calc calc.txt
- 执行
grun Calc prog -gui calc.txt
3+6*8-9/(7-4)
2*3-6+4
9/3+(6/2)
5*4+((6*7)-(3*2))/4
总结
以上就是Antlr计算器入门案例,本文仅仅简单介绍了Antlr最基本的使用方法,而Antlr提供的大量功能还需继续学习。 愿这篇博客能帮助到你ヾ(≧▽≦*)o