背景
之前在做游戏的过程中,我们经常需要解析一些公式,比如(对方攻击值-对方防御值)*2这种表达式,我们习惯于用代码写死公式,但是这种方式不够灵活,我们想要的是一种灵活的解析方式,
只需要策划输入一个任意的一个表达式,我们就可以自动计算出来对应的数值,我们不需要理解策划的公式,那么问题就转化成了如何解析表达式公式呢?答案是使用antlr.
技术实现
antlr是一个解析器,包括两个部分:词法解析器和语法解析器,如下图所示:
antlr最大的优点是可以按照树的深度优先遍历访问所有的节点,比如下面的表达式:
(1) + 10 * 20 - 40/2 - (attack + defence)
如果我们使用简单的如下.g4文件来解析的话,
grammar Calc;
prog
: stat+
;
stat
: expr # printExpr
| ID '=' expr # assign
;
expr
: expr (MUL|DIV) expr # MulDiv
| expr (ADD|SUB) expr # AddSub
| INT # int
| ID # id
| '(' expr ')' # parens
;
MUL : '*' ;
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
ID : [a-zA-Z]+ ;
INT : [0-9]+ ;
WS : [ \t\r\n]+ -> skip ; // toss out whitespace
antlr可以解析成如下的解析树:
我们可以看出来如果我们编写一个Listener访问这棵树的话,我们可以得到完整的表达式,包括各个优先级都是正确的,当获取到这个按正确优先级排好序的指令后,我们可以通过简单的堆栈操作获取结果:
push(1)
push(10)
push(20)
pop(*)
pop(+)
push(40)
push(2)
pop(/)
pop(-)
push(attack)
push(defence)
pop(-)
pop(-)
注意这是一个深度优先遍历树的顺序,通过这个指令顺序,可以获取正确的表达式的值
总结
antlr提供了一种解析表达式的方便的方式,让我们可以解析任何用户或者策划提供的公式,它会按照深度优先树遍历的顺序返回数据和指令的顺序,方便我们计算最终的结果