Goland 中Antlr4外掛
在goland中安裝Antlr4外掛,用於識別輸入的字元在在語法檔案中生成的語法樹的樣子,大概就是如下的摸樣
下載步驟:
1.點選檔案中的設定選項
2.在外掛目錄下輸入Antlr4搜尋外掛
3.點選安裝即可
編寫自己的語言語法檔案
編寫語法之前,我們首先要構思一下自己的DSL都有什麼關鍵字,這是個重要的步驟,就像我們學習java或者Golang一樣,首先知道這個語法裡面都有那些關鍵字。
我定義的DSL中有四則運算,有比較運算,還有邏輯運算,變數可以有數字、字串、時間格式
關鍵字
四則運算
作用 | 符號 |
---|---|
乘法 | * |
除法 | / |
加法 | + |
減法 | - |
比較運算
作用 | 符號 |
---|---|
等於 | = |
不等於 | <> |
大於 | > |
大於等於 | >= |
小於 | < |
小於等於 | <= |
邏輯運算
作用 | 符號 |
---|---|
且 | && |
或 | || |
如果 | if |
否則 | else |
變數
作用 | 符號 |
---|---|
數字 | ('0' | [1-9] ('_'? [0-9])*) |
文字 | [\p{Nd}] |
字串 | LETTER (LETTER |
日期 | ([0-9]{4}/[0-1]{0,1}[0-9]/[0-3]{0,1}[0-9]) |
常量輔助符號
作用 | 符號 |
---|---|
點 | . |
逗號 | , |
左括號 | ( |
右括號 | ) |
分號 | ; |
多行註釋 | '/*' .*? '*/' |
上述就是我們的Token列表,可以建立一個文法檔案單獨寫Token,文法檔案申明:lexer grammar Lexer;
編寫語法
編寫語法之前,我們需要構思一下,我們的DSL可以支援那些語法操作,例如四則運算可以支援字串運算嗎?日期支援四則運算嗎?我們可以從基礎開始編寫,例如我們把變數使用算則模式編寫成一個語法規則,
simpleStmt:NUMBER|TEXT|STRING|DATE
我的DSL中支援任何資料的四則運算,那麼我就可以使用simpleStmt和四則運算子號組成四則運算
expression:
simpleStmt #SimpleExpression
|expression op = (MUL|DIV) expression #MulDiv
|expression op = (ADD|SUB) expression #AddSub
;
這時候我們就定義了支援四則運算的語法規則,我們來試一下語法定義的對不對。
發現我們輸入的加法運算和乘法運算都可以被解析,說明我們的語法定義正確。接下來我們新增比較運算
我定義的DLS支援所有資料做比較運算,那麼我直接在上面的expression中新增比較運算就可以了,這裡需要注意的是比較運算如果希望有優先順序,需要先定義優先順序高的比較符號,我這裡沒有優先順序操作,所以都是平級的。
新增比較運算子號
expression:
simpleStmt #SimpleExpression
|expression op = (MUL|DIV) expression #MulDiv
|expression op = (ADD|SUB) expression #AddSub
|expression op = (EQ|NE|LT|LE|GT|GE) expression #Compare
;
驗證一下比較運算語法定義的是否正確。
發現沒有錯誤,正確解析出樹就代表語法定義的正確。接下來大家可以自己構思一下剩下的語法規則,或者新增自己的語法規則了。大概思路就是先想一個語法希望是什麼樣,然後編寫語法規則,然後輸入希望的格式驗證語法規則。
編寫Listener
還是老樣子,編寫號語法檔案,我們執行Antlr4生成執行時語言為Go的命令:
java -jar 'C:\Program Files\Java\antlr\antlr-4.12.0-complete.jar' -Dlanguage=Go -no-visitor -package parser *.g4
編寫監聽器類
type CalcListener struct{
*parser.BaseCalcListener //繼承Listener基類
*antlr.DefaultErrorListener //繼承錯誤基類
}
//發生錯誤時,處理錯誤
func (l *CalcLister) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
}
//退出MulDiv語法時
func (l *CalcLister) ExitMulDiv(c *parser.MulDivContext) {
}
//退出AddSub語法時
func (l *CalcLister) ExitAddSub(c *parser.AddSubContext) {
}
//退出數字語法時
func (l *CalcLister) ExitNumber(c *parser.NumberContext) {
}
這裡細心的小夥伴已經發現,在語法檔案中使用“#”指定的節點名稱在監聽器中回生成一個節點方法,在Antlr4中,“#”號代表手動指定語法規則名稱,需要注意的是,不要跟Token和規則名稱重複。
遍歷語法樹
Antlr4遍歷語法樹時,使用DFS方式遍歷樹
監聽模式和訪問模式
Antlr4提供了兩種遍歷語法樹的方式,監聽模式和訪問模式,預設是監聽模式,如果希望使用訪問模式的話,需要修改命令:
java -jar 'C:\Program Files\Java\antlr\antlr-4.12.0-complete.jar' -Dlanguage=Go -visitor -package parser *.g4
這樣會生成訪問者模式和監聽者模式
calc_base_listener.go //監聽者模式基類檔案
calc_base_visitor.go //訪問者模式基類檔案
訪問者模式:先遍歷父節點,然後遍歷子節點
監聽者模式:Enter先進入父節點,Exit最後退出父節點
個人建議還是使用監聽者模式,在Enter控制子節點訪問,Exit做父節點子樹執行邏輯。訪問者模式控制能力更強,監聽者模式需要遍歷整個樹。
至此,使用golang+Antlr4就可以定義一個屬於自己的語法規則的解析器了,如果有哪裡不同的可以給小編留言,我們共同學習!!!