2017年9月3日 星期日

ANTLR v4--入門

今天我想介紹一個強大有趣的工具--ANTLR
這個工具根據我們定義的文法產生處理原始碼的parser,當然不只是處理程式語言,你也可以用來處理其他資料

= 安裝
cd /usr/local/lib
sudo 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'
之後會用到的通常是antlr4這支程式
因為它用來產生parser

= 開始
我們需要建立一個檔案叫xxx.g4,而裡頭的grammar就必須是grammar xxx;
舉例來說JSON.g4就會是
grammar JSON;

接下來我們談ANLTR的語法還有它如何運作
首先如果你接觸過v3以前的antlr,那麼你一定知道embbed action
不過這個版本的antlr並不需要全都使用embbed action來實現程式邏輯

反之它加入了xxxBaseListener來處理大部分的翻譯過程
你也可以選擇Visitor來實作,但是visitor需要顯式的調用Context,並不適合大型複雜的文法
Listener則能應付絕大多數的情況,它的API都是enterXxx跟exitXxx的格式,名稱相當直觀

= 約定
ANTLR要求Token使用大寫英文字母開頭,grammar則使用小寫
例如
NUM : [0-9]+ ;
ID : [a-z]+ ;

stat : ID '=' expr
    | expr
    ;

expr : NUM
    | ID
    ;
ID跟NUM都是token,stat跟expr則是文法規則
表示不同的可能
表示規則結束

可以看到如果我們想要辨別符號,必須用''包起來,除了符號,關鍵字也要這樣處理,像這樣
Class : 'class' ;

表示一個或無限多個
表示沒有或無限多個
表示有或沒有

定義ID跟NUM時,我都使用了正規表達式來處理,這是為了方便而放入的功能
你也可以選擇
NUM : ('0' .. '9')+ ;
這種寫法

最後就是產生parser
antlr4 -Dlanguage=Cpp JSON.g4
-Dlanguage 指定產生什麼語言的parser
這裡是C++
如果不指定,那麼預設是Java
目前支援Java, C#, Python2|3, JavaScript, Go, C++, Swift
儘管選擇你習慣的那個

為什麼要學Antlr?
事實上編譯技術在很多地方都有用途
例如Firefox團隊為了加速JavaScript eval函式的執行速率,在編譯到eval時會進行預處理,讓JavaScript真的執行到這邊時已經少了許多工作
簡單一些的應用可能有:編寫DSL簡化開發工作
例如新增網路服務API,如果用特製的語言將工作進行簡化
routes:
    get "/":
        resp Page1
那麼我們實際上需要負擔的工作量就大幅縮小了吧!
而且亦便於未來的維護工作,而DSL最棒的要點就在於,我們往往無須實現完整的通用語言
比如我們可以在回傳的區塊回到Java語言
routes:
    get "/":
        @java {
            // ... Your java code
        }
這樣我們就不需要實現太過麻煩的東西
而一樣能享受DSL的方便度

沒有留言:

張貼留言