定义语法

Calc.g4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
grammar Calc;

prog: stat+;

stat: expr NEWLINE # printExpr
| NEWLINE # blank
;

expr: expr MUL expr # Mul
| expr DIV expr # Div
| expr ADD expr # Add
| expr SUB expr # Sub
| INT # int
| '(' expr ')' # parens
;

MUL : '*' ;
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
INT : [0-9]+ ;
NEWLINE:'\r'? '\n' ;
WS : [ \t]+ -> skip;

生成代码

使用插件或者 jar 根据语法生成代码。
安装 idea 插件


生成词法分析和语法分析的代码

编写程序代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package io.github.lmikoto.calc;

import io.github.lmikoto.calc.gen.CalcBaseVisitor;
import io.github.lmikoto.calc.gen.CalcParser;

/**
* @author 刘阳
* @date 2021/9/18 1:01 下午
*/
public class CalcEvalVisitor extends CalcBaseVisitor<Integer> {

@Override
public Integer visitPrintExpr(CalcParser.PrintExprContext ctx) {
return visit(ctx.expr());
}

@Override
public Integer visitInt(CalcParser.IntContext ctx) {
return Integer.valueOf(ctx.INT().getText());
}

@Override
public Integer visitMul(CalcParser.MulContext ctx) {
Integer left = visit(ctx.expr(0));
Integer right = visit(ctx.expr(1));
return left * right;
}

@Override
public Integer visitDiv(CalcParser.DivContext ctx) {
Integer left = visit(ctx.expr(0));
Integer right = visit(ctx.expr(1));
return left / right;
}

@Override
public Integer visitAdd(CalcParser.AddContext ctx) {
Integer left = visit(ctx.expr(0));
Integer right = visit(ctx.expr(1));
return left + right;
}

@Override
public Integer visitSub(CalcParser.SubContext ctx) {
Integer left = visit(ctx.expr(0));
Integer right = visit(ctx.expr(1));
return left - right;
}

@Override
public Integer visitParens(CalcParser.ParensContext ctx) {
return visit(ctx.expr());
}
}

编写 main 方法执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package io.github.lmikoto.calc;

import io.github.lmikoto.calc.gen.CalcLexer;
import io.github.lmikoto.calc.gen.CalcParser;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CodePointCharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

public class Calc {

public static void main(String[] args) {

CodePointCharStream inputStream = CharStreams.fromString("6 + (1 + 5) * 4+ 6 / 2 \n");
CalcLexer lexer = new CalcLexer(inputStream);

CommonTokenStream tokenStream = new CommonTokenStream(lexer);
CalcParser parser = new CalcParser(tokenStream);
ParseTree parseTree = parser.prog();
CalcEvalVisitor visitor = new CalcEvalVisitor();
Integer rtn = visitor.visit(parseTree);
System.out.println(rtn);
}
}