Antlr4+python3-visitor使用(四则运算解析)

Antlr系列(配合Python3)文章:https://www.jianshu.com/nb/32570686

Visitor实现四则运算的计算

文法规则文件Expr.g4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
grammar Expr;		
prog: expr NEWLINE # printExpr;
expr: left=expr op=('*'|'/') right=expr # mulDiv // 用来确定优先级,在上面的优先级高
| left=expr op=('+'|'-') right=expr # addSub
| INT # int
| '(' expr ')' # brackets
;
NEWLINE : [\r\n]+ ;
INT : [0-9]+ ;

MUL : '*' ; // 用来便于当作常量引用
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;

在执行antlr4的时候需要指明-no-listener-visitor,因此执行antlr4 -no-listener -visitor -Dlanguage=Python3 Expr.g4

创建文件Expr.py

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
import sys
from antlr4 import *
from ExprLexer import ExprLexer
from ExprParser import ExprParser
from ExprVisitor import ExprVisitor

class ExprCalculateVisitor(ExprVisitor):
def visitPrintExpr(self, ctx):
# 函数名enterR的R指的是非终结符r
val = self.visit(ctx.expr())
print(val)
return val

def visitBrackets(self, ctx):
return self.visit(ctx.expr())

def visitAddSub(self, ctx):
if ctx.op.type == ExprParser.ADD:
return self.visit(ctx.left) + self.visit(ctx.right)
else:
return self.visit(ctx.left) - self.visit(ctx.right)

def visitMulDiv(self, ctx):
if ctx.op.type == ExprParser.MUL:
return self.visit(ctx.left) * self.visit(ctx.right)
else:
return self.visit(ctx.left) / self.visit(ctx.right)

def visitInt(self, ctx):
return int(ctx.getText())


def main():
lexer = ExprLexer(StdinStream())
stream = CommonTokenStream(lexer)
parser = ExprParser(stream)
tree = parser.prog()
calculator = ExprCalculateVisitor()
calculator.visitPrintExpr(tree)

if __name__ == '__main__':
main()

这里的visitXXX的XXX部分都是上面#后的内容;如果不写#后的东西,就会是visitProg之类的

之后仍然是运行并且输入后回车输入EOF(Ctrl-D/Ctrl-Z)即可看到结果输出