對於寫一個本身的解析器這回事,我之前歷來沒有想過的,畢竟我學渣,並且還沒學過編譯原理。
可是沒想到到新公司居然這等美差還能落到我頭上,真是要好好感謝下大佬們。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 方法