对于写一个本身的解析器这回事,我之前历来没有想过的,毕竟我学渣,并且还没学过编译原理。
可是没想到到新公司居然这等美差还能落到我头上,真是要好好感谢下大佬们。html
言归
郑传java
虽然之前没有写过解析器,可是作过相关的事情。在之前的一家公司时曾经写过规则,就是那种业务开始复杂后,逻辑很差写死在程序中,须要根据业务改变,而动态配置规则。这个东西是在odoo下作的,用的它提供的asteval。python
简而言之,就是用odoo 封装过得eval 来执行一段 python code 而返回结果。git
而如今公司的业务需求是风控部门定义本身的风控规则,而咱们去解析这些规则。 这个就跟之前是倒过来。这里以前没明白为何不用python的解释器去解析这些规则,后面作实际作了事后才知道,这样更面向风控规则,且能够高于python之上。也就是说咱们能够根据风控规则的形式,自定义一些规范,而后解析器去解析这些既定规范就好。感受高端了不少。github
PLY(lexer/yacc) 是入门简单,可是实现一些东西有难度。好比实现一个if条件判断,须要多作一点事情。否则就会获得错误的结果。好比算法
a=1; if("a") a=2 else a=4
最开始获得的结果是4,由于ply是自下向上解析,每一个字符都会被执行到,而后你的逻辑须要单独写算法实现。curl
而antlr是入门困难,用起来很方便。个人比喻是ply像汇编语言,antlr是高级语言优化
要使用antlr,须要先准备 antlr 的编译环境。antlr 的规则是写好词法规则跟语法规则,而后用antlr去编译生成对应语言的应用,而后再去作相应的实现就行。ui
$ cd /usr/local/lib $ curl -O http://www.antlr.org/download/antlr-4.7-complete.jar $ export CLASSPATH=".:/usr/local/lib/antlr-4.7-complete.jar:$CLASSPATH" $ alias antlr4='java -jar /usr/local/lib/antlr-4.7-complete.jar' $ alias grun='java org.antlr.v4.gui.TestRig'
这里我使用python 来实现antlr,因此我须要安装antlr 的pyhon执行环境url
pip install antlr4-python3-runtime
or
pip install antlr4-python2-runtime
若是你故意写错一个词法, antlr 默认的词法解析错误会报错,可是会尽可能去按照正确的角度解析,结果仍是正确的!
这种咱们须要重写它的错误处理,解析错误就扔出异常。
public class HyperRuleBailLexer extends HyperRuleLexer { public HyperRuleBailLexer(CharStream input) { super(input); } public void recover(LexerNoViableAltException e) { throw new RuntimeException(e); } }
用HyperRuleBailLexer去实例化一个 lexer 对象
java 跟Python 版本的语法错误都会抛异常,在the-definitive-antlr-4-reference书中提到了优化异常处理。在antlr4不须要咱们再去实现 BailErrorStrategy, antlr的依赖中有这个类,只须要给解析器注入下错误处理
HyperRuleParser parser = new HyperRuleParser(tokenStream); parser.setErrorHandler(new BailErrorStrategy());
使用
HyperRuleParser parser = new HyperRuleParser(tokenStream); parser.setErrorHandler(new BailErrorStrategy());
注意:以上代码只有在java中,python 没有setErrorHandler 方法