Antrl4入門、安裝、案例

前言

總監:阿毛啊,下面咱們負責的項目你負責詞法、語法那塊的工作吧?

我:emmm........詞法語法我倒是大學有學過,編譯原理????大學學的就不好,難於上青天啊。。

總監:你覺得有什麼問題嗎?

我:好的(內心一萬個拒絕),我前期先調研一下吧。

總監:好的這個功能比較難,好好用心啊。畫大餅開始。。。。

經過幾天的調研分析,antlr是最適合不過的了。下面咱們就一起學習一下吧。


ANTLR 官方網址 http://www.antlr.org/

ANTLR 官方 Github https://github.com/antlr/antlr4

大量語法文件例子 https://github.com/antlr/grammars-v4

Antrl4入門、安裝、案例

Antlr是什麼?

Antlr是一款強大的語法分析器生成工具,可用於讀取、處理、執行和翻譯結構化的文本或二進制文件。它被廣泛的應用於學術領域和工業生產實踐,是眾多語言、工具和框架的基石。Twitter所使用Antlr進行語法分析,每天超過20億次查詢,Hadoop生態環境中的Hive、Pig、數據倉庫和分析系統所使用的分析系統都使用到了Antlr。

Antlr是用JAVA寫的語言識別工具,它用來聲明語言的語法,簡稱為“元語言”(meta-language)。

Antlr 語法識別一般分為二個階段:

1.詞法分析階段 (lexical analysis)

對應的分析程序叫做 lexer ,負責將符號(token)分組成符號類(token class or token type)

2.解析階段

根據詞法,構建出一棵分析樹(parse tree)或叫語法樹(syntax tree)

Antrl4入門、安裝、案例

主要應用場景

1.定製特定領域語言(DSL)

類似hibernate中的HQL,用DSL來定義要執行操作的高層語法,這種語法接近人可理解的語言,由DSL到計算機語言的翻譯則通過ANTLR來做,可在ANTLR的結構語言中定義DSL命令具體要執行何種操作。

2.文本解析 可利用ANTLR解析JSON,HTML,XML,EDIFACT,或自定義的報文格式。解析出來的信息需要做什麼處理也可以在結構文件中定義。

3.數學計算 加減乘除,線性方程,幾何運算,微積分等等

ANTRL 語法

結構

<code>/** Optional javadoc style comment */
grammar Name;
options {...}
import ... ;

tokens {...}
channels {...} // lexer only
@actionName {...}

rule1 // parser and lexer rules, possibly intermingled
...
ruleN/<code>

grammar

<code>grammar  SPL;/<code>

options

選項,如語言選項,輸出選項,回溯選項,記憶選項等等

<code>options { output=AST;  language=Java; }

options { tokenVocab=MySqlLexer; }/<code>

@actionName

動作(Actions)實際上是用目標語言寫成的、嵌入到規則中的代碼(以花括號包裹)。它們通常直接操作輸入的標號,但是他們也可以用來調用相應的外部代碼。屬性,到目前為止我的理解還不多,感覺像是C++中類裡面的成員。常用屬性或動作說明:

  • @header { package com.zetyun.aiops.antlr.test; }這個動作很有用,即在運行腳本後,生成的類中自動帶上這個包路徑,避免了手動加入的麻煩。
  • @members { int i; public TParser(TokenStream input, int foo) { this(input); i = foo; }}
  • @after {System.out.println("after matching rule; before finally");}

rule

這是核心,表示規則,以 “:” 開始, “;” 結束, 多規則以 "|" 分隔。

<code>ID : [a-zA-Z0-9|'_']+ ;    //數字 
STR:'\\'' ('\\'\\'' | ~('\\''))* '\\'';
WS: [ \\t\\n\\r]+ -> skip ; // 系統級規則 ,即忽略換行與空格

sqlStatement
: ddlStatement
| dmlStatement | transactionStatement
| replicationStatement | preparedStatement
| administrationStatement | utilityStatement
;/<code>

2.註釋

  • 單行、多行、javadoc風格
  • javadoc風格只能在開頭使用
<code>/** 
* This grammar is an example illustrating the three kinds
* of comments.
*/
grammar T;

/* a multi-line
comment
*/

/** This rule matches a declarator for my language */

decl : ID ; // match a variable name/<code>

3.標識符

  • 符號(Token)名大寫開頭
  • 解析規則(Parser rule)名小寫開頭,後面可以跟字母、數字、下劃線
<code>ID, LPAREN, RIGHT_CURLY // token names
expr, simpleDeclarator, d2, header_file // rule names/<code>

g4文件實踐例子和解釋

<code>grammar Dsl;    //定義規則文件grammar
@header { //一種action,定義生成的詞法語法解析文件的頭,當使用java的時候,生成的類需要包名,可以在這裡統一定義
package antlr;
}

//parsers
sta:(sql ender)*; //定義sta規則,裡面包含了*(0個以上)個 sql ender組合規則
ender:';'; //定義ender規則,是一個分號
sql //定義sql規則,sql規則有兩條分支:select/load
: SELECT ~(';')* as tableName //select語法規則,以lexer SELECT開頭, 以as tableName 結尾,其中as 和tableName分別是兩個parser
| LOAD format '.' path as tableName //load語法規則,大致就是 load json.'path' as table1,load語法裡面含有format,path, as,tableName四種規則
; //sql規則結束符
as: AS; //定義as規則,其內容指向AS這個lexer
tableName: identifier; //tableName 規則,指向identifier規則
format: identifier; //format規則,也指向identifier規則
path: quotedIdentifier; //path,指向quotedIdentifier
identifier: IDENTIFIER | quotedIdentifier; //identifier,指向lexer IDENTIFIER 或者parser quotedIdentifier
quotedIdentifier: BACKQUOTED_IDENTIFIER; //quotedIdentifier,指向lexer BACKQUOTED_IDENTIFIER

//lexers antlr將某個句子進行分詞的時候,分詞單元就是如下的lexer
//keywords 定義一些關鍵字的lexer,忽略大小寫
AS: [Aa][Ss];
LOAD: [Ll][Oo][Aa][Dd];
SELECT: [Ss][Ee][Ll][Ee][Cc][Tt];

//base 定義一些基礎的lexer,
fragment DIGIT:[0-9]; //匹配數字
fragment LETTER:[a-zA-Z]; //匹配字母
STRING //匹配帶引號的文本
: '\\'' ( ~('\\''|'\\\\') | ('\\\\' .) )* '\\''
| '"' ( ~('"'|'\\\\') | ('\\\\' .) )* '"'
;
IDENTIFIER //匹配只含有數字字母和下劃線的文本
: (LETTER | DIGIT | '_')+
;
BACKQUOTED_IDENTIFIER //匹配被``包裹的文本
: '`' ( ~'`' | '``' )* '`'
;

//--hiden 定義需要隱藏的文本,指向channel(HIDDEN)就會隱藏。這裡的channel可以自定義,到時在後臺獲取不同的channel的數據進行不同的處理
SIMPLE_COMMENT: '--' ~[\\r\\n]* '\\r'? '\\n'? -> channel(HIDDEN); //忽略行註釋
BRACKETED_EMPTY_COMMENT: '/**/' -> channel(HIDDEN); //忽略多行註釋
BRACKETED_COMMENT : '/*' ~[+] .*? '*/' -> channel(HIDDEN) ; //忽略多行註釋
WS: [ \\r\\n\\t]+ -> channel(HIDDEN); //忽略空白符

// 匹配其他的不能使用上面的lexer進行分詞的文本
UNRECOGNIZED: .;/<code>

四.遍歷模式

1、Listener (觀察者模式,通過結點監聽,觸發處理方法)

  • 程序員不需要顯示定義遍歷語法樹的順序,實現簡單
  • 缺點,不能顯示控制遍歷語法樹的順序
  • 動作代碼與文法產生式解耦,利於文法產生式的重用
  • 沒有返回值,需要使用map、棧等結構在節點間傳值

2、Visitor (訪問者模式,主動遍歷)

  • 程序員可以顯示定義遍歷語法樹的順序
  • 不需要與antlr遍歷類ParseTreeWalker一起使用,直接對tree操作
  • 動作代碼與文法產生式解耦,利於文法產生式的重用
  • visitor方法可以直接返回值,返回值的類型必須一致,不需要使用map這種節點間傳值方式,效率高

安裝Antlr4步驟

下載Java安裝

我使用的是Java8,這裡就不詳細介紹Java的安裝了。

1.下載antlr-4.7.2-complete.jar

https://www.antlr.org/download/antlr-4.7.2-complete.jar

Linux下的安裝方式:

<code>$ cd /usr/local/lib
$ sudo curl -O https://www.antlr.org/download/antlr-4.7.2-complete.jar/<code>

2.新建運行腳本 antlr4.bat 和 grun.bat,放置於任意目錄,如 E:/tools/antlr4

antlr4.bat 內容:

<code>java org.antlr.v4.Tool %*/<code>

grun.bat 內容:

<code>java org.antlr.v4.gui.TestRig %*/<code>

注:antlr依賴於java,如果java環境變量沒有設置,請先行設置好。

3.設置antlr4的系統環境變量

Windows環境配置:

<code>E:/tools/antlr4/antlr-4.7.2-complete.jar
E:/tools/antlr4/<code>
Antrl4入門、安裝、案例

Windows環境變量配置

Linux及Mac:

<code>// 設置環境變量
$ vim .bash_profile
$ export CLASSPATH=".:/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH"
$ alias antlr4='java -jar /usr/local/lib/antlr-4.7.2-complete.jar'
$ alias grun='java org.antlr.v4.gui.TestRig'
$ wq
$ source .bash_profile /<code>

是否安裝成功測試

<code>$ antlr4
ANTLR Parser Generator Version 4.7.2
-o ___ specify output directory where all output is generated
-lib ___ specify location of grammars, tokens files
-atn generate rule augmented transition network diagrams
-encoding ___ specify grammar file encoding; e.g., euc-jp
-message-format ___ specify output style for messages in antlr, gnu, vs2005
-long-messages show exception details when available for errors and warnings
-listener generate parse tree listener (default)
-no-listener don't generate parse tree listener
-visitor generate parse tree visitor
-no-visitor don't generate parse tree visitor (default)
-package ___ specify a package/namespace for the generated code
-depend generate file dependencies
-D<option>=value set/override a grammar-level option
-Werror treat warnings as errors
-XdbgST launch StringTemplate visualizer on generated code
-XdbgSTWait wait for STViz to close before continuing
-Xforce-atn use the ATN simulator for all predictions
-Xlog dump lots of logging info to antlr-timestamp.log
-Xexact-output-dir all output goes into -o dir regardless of paths/package

$ grun
java org.antlr.v4.gui.TestRig GrammarName startRuleName
[-tokens] [-tree] [-gui] [-ps file.ps] [-encoding encodingname]
[-trace] [-diagnostics] [-SLL]
[input-filename(s)]
Use startRuleName='tokens' if GrammarName is a lexer grammar.
Omitting input-filename makes rig read from stdin./<option>/<code>
Antrl4入門、安裝、案例

安裝成功

Java實踐例子

<code>$ mkdir test
$ cd test/
$ vim Hello.g4

輸入:
// Define a grammar called Hello
grammar Hello;
r : 'hello' ID ; // match keyword hello followed by an identifier
ID : [a-z]+ ; // match lower-case identifiers
WS : [ \\t\\r\\n]+ -> skip ; // skip spaces, tabs, newlines

$ wq! // 保存
$ antlr4 Hello.g4
$ ls
Hello.g4\t\tHelloBaseListener.java\tHelloLexer.tokens
Hello.interp\t\tHelloLexer.interp\tHelloListener.java
Hello.tokens\t\tHelloLexer.java\t\tHelloParser.java


$ javac Hello*.java
$ ls
Hello.g4\t\t\tHelloLexer.java
Hello.interp\t\t\tHelloLexer.tokens
Hello.tokens\t\t\tHelloListener.class
HelloBaseListener.class\t\tHelloListener.java
HelloBaseListener.java\t\tHelloParser$RContext.class
HelloLexer.class\t\tHelloParser.class
HelloLexer.interp\t\tHelloParser.java

$ grun Hello r -gui // 按回車
hello nihao // 輸入這個,再按回車
^D // 按ctrl+D 就出現gui圖形界面了
/<code>
Antrl4入門、安裝、案例

GUI界面

Antrl4入門、安裝、案例

java編譯過程

Python實踐例子

和生成Java代碼類似,不同的地方在於編譯g4文件命令:

<code>antlr4 -Dlanguage=Python3 -visitor Expr.g4/<code>

這樣就會生成python代碼:

<code>➜  antlr4 -Dlanguage=Python3 Hello.g4 
➜  ls
Hello.g4          Hello.tokens      HelloLexer.py     HelloListener.py
Hello.interp      HelloLexer.interp HelloLexer.tokens HelloParser.py/<code>
Antrl4入門、安裝、案例

python編譯

當然還可以生成其他代碼,感興趣的可以嘗試學一下。

總結

上面就是我在學習Antlr中所瞭解的知識,歡迎大家指正,一起學習,一起進步。

關注私信小編,Antlr權威指南分享給你,另外小編會不定時分享一些學習知識點。一起學習吧。

Antrl4入門、安裝、案例


分享到:


相關文章: